以太坊 - 深入浅出虚拟机

星想法  2019-04-09  以太坊/以太坊(Ethereum)栏目  
创业有三种状态:投机,寻租以及自恋。屌丝程序员发现区块链是快速改变自己阶级命运的神器,一股脑冲进去,这是投机。早期的创业者,初初接触商业,寻求各种社会资源,各种“优惠”,努力实现“旱涝保收”的状态,这是寻租。稳定盈利的创业者会自恋,认为自己无所不能。创业过程会在这三种状态之间徘徊。在每个状态都要理智控制自己的情绪和理智。创业,最美妙的心理历程是以自己可控方式进入自恋的状态,做自己想做的事情,反推现状,寻找破局。

  以太坊虚拟机,简称EVM,是用来执行以太坊上的交易的。业务流程如下图:

  

  输入一笔交易,内部会转换成一个Message对象,传入EVM执行。

  如果是一笔普通转账交易,那么直接修改StateDB中对应的账户余额即可。如果是智能合约的创建或者调用,则通过EVM中的解释器加载和执行字节码,执行过程中可能会查询或者修改StateDB。

01固定油费(Intrinsic Gas)

  每笔交易过来,不管三七二十一先需要收取一笔固定油费,计算方法如下:

  

  如果你的交易不带额外数据(Payload),比如普通转账,那么需要收取21000的油费。

  如果你的交易携带额外数据,那么这部分数据也是需要收费的,具体来说是按字节收费:字节为0的收4块,字节不为0收68块,所以你会看到很多做合约优化的,目的就是减少数据中不为0的字节数量,从而降低油费消耗。

02生成CONTract对象

  交易会被转换成一个Message对象传入EVM,而EVM则会根据Message生成一个Contract对象以便后续执行:

  

  可以看到,Contract中会根据合约地址,从StateDB中加载对应的代码,后面就可以送入解释器执行了。

  另外,执行合约能够消耗的油费有一个上限,就是节点配置的每个区块能够容纳的GasLimit。

03送入解释器执行

  代码跟输入都有了,就可以送入解释器执行了。EVM是基于栈的虚拟机,解释器中需要操作四大组件:

  PC:类似于CPU中的PC寄存器,指向当前执行的指令

  Stack:执行堆栈,位宽为256 bits,最大深度为1024

  Memory:内存空间

  Gas:油费池,耗光邮费则交易执行失败

  

  具体解释执行的流程参见下图:

  

  EVM的每条指令称为一个OpCode,占用一个字节,所以指令集最多不超过256,具体描述参见:https://ETHervm.io。比如下图就是一个示例(PUSH1=0x60, MSTORE=0x52):

  

  首先PC会从合约代码中读取一个OpCode,然后从一个JumpTable中检索出对应的operation,也就是与其相关联的函数集合。接下来会计算该操作需要消耗的油费,如果油费耗光则执行失败,返回ErrOutOfGas错误。如果油费充足,则调用execute()执行该指令,根据指令类型的不同,会分别对Stack、Memory或者StateDB进行读写操作。

04调用合约函数

  前面分析完了EVM解释执行的主要流程,可能有些同学会问:那么EVM怎么知道交易想调用的是合约里的哪个