接着上次的分析,分析一下run方法是如何执行智能合约的。至于以太币的交易,在上一篇中,已经由分析的那两个函数完成了;

合约的运行是从run开始的,go-ethereum/core/vm/evm.go 。可以分为两部分一部分是预编译,另外一部分是解释器。

预编译合约

// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
precompiles = PrecompiledContractsByzantium
}
if p := precompiles[*contract.CodeAddr]; p != nil {
return RunPrecompiledContract(p, input, contract)
}
}
return evm.interpreter.Run(contract, input)
}
     在以太坊中,go-ethereum/core/vm/contracts.go,事先编译好了一组合约,具体如下:

var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256Add{},
common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
common.BytesToAddress([]byte{8}): &bn256Pairing{},
}
    如果要执行的contract恰好属于预编译的合约集合,那么它就可以直接运行;由于预编译的合约内容是固化在以太坊中的,所以我们输入参数即可(input),不需要输入合约内容(code)。

type PrecompiledContract interface {
RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
}
    每个预编译的合约都有两个方法,第一个是计算需要花费gas,第二个是合约的具体实现。如果是基于evm开发的公链,我们完全可以自己开发出更多的预编译合约,这样运行速度会增加很多。

解释器

不属于预编译的contract,则由Interpreter解释执行。 这里 我们需要看一下上一篇文章中的EVM框架图。

EVMInterpreter中存在一个config结构体,其中包含一个JumpTable数组,这个数组包含了256个operation对象;每个operation对象是一个指令,指令由四个函数组成——execute、gascost、validatestack、memory size;而operation执行时,会用到stack、memory,statedb。

execute:指令执行函数

gascost:gas计算

validatestack:栈深度检测

memorysize:内存消耗

contract则是智能合约对象,其中code则是合约代码,不过是已经转化为指令的代码,

从上图我可以看到,解释器的run()函数执行过程很简单;就是contract的code中的指令,依次通过jumptable找到对应operation;然后由opertation中四个函数实现指令的执行。

这是run()函数的主流程;由栈(stack)负责保存操作数,所有的操作都是运行在栈上的;内存(memory)数据结构是一个byte数组,用于一些内存操作(MLOAD,MSTORE,MSTORE8)及合约调用的参数拷贝(CALL,CALLCODE)。

每个节点都有一个EVM,为了严重交易,每一笔交易都会在每个节点的EVM都会运行一遍,很明显这样会造成计算资源的浪费。而从安全性的方面考虑,在一个区块链系统中,一但系统中节点的状态出现不同的状态,各个节点的EVM运行智能合约时,会出现错误,导致系统无法到达一致,达成共识;这就要求整个系统必须再次达成一致性。

以太坊 EVM内交易执行分析(二)的更多相关文章

  1. 以太坊 EVM内交易执行分析(一)

    以太坊上交易最终都会由EVM进行解析存入数据库,今天就来探讨一下,一笔交易是如何别EVM执行的.我们可以把交易分为三种.(注意,和交易相关的模块很多,交易的生命周期存在于整个以太坊中,我们这次只是分析 ...

  2. 以太坊 layer2: optimism 源码学习(二) 提现原理

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...

  3. 以太坊: ETH 发送交易 sendRawTransaction 方法数据的签名 和 验证过程

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  4. 以太坊EVM在安全性方面的考虑

    以太坊上用户编写的合约是不可控的,要保证这些合约能够正确执行并且不会影响区块链的稳定,虚拟机需要做安全方面的考虑. 1 在程序执行过程中采取的每个计算步骤都必须提前支付费用, 从而防止DoS攻击.先消 ...

  5. c#实战开发:以太坊钱包对接私链 (二)

    上一篇讲了 以太坊私链搭建 首先下载Ethereum Wallet 钱包 可以直接百度 下载如果直接打开它会默认连接公链 所以我们要通过命令打开 "F:\Program Files\Ethe ...

  6. 以太坊go-ethereum客户端docker安装(二)开发(dev)环境搭建

    在上一篇博客中,讲述了基于docker怎么搭建一个go-ethereum节点.作为开发人员,如果只是单纯的拥有一个Full node,还无法满足正常的开发.比如说,进行转账交易,你要考虑是否拥有一定的 ...

  7. ethereum(以太坊)(基础)--容易忽略的坑(二)

    pragma solidity ^0.4.0; contract EMath{ string public _a="lin"; function f() public{ modif ...

  8. 死磕以太坊源码分析之txpool

    死磕以太坊源码分析之txpool 请结合以下代码阅读:https://github.com/blockchainGuide/ 写文章不易,也希望大家多多指出问题,交个朋友,混个圈子哦 交易池概念原理 ...

  9. 以太坊中的账户、交易、Gas和区块Gas Limit等概念

    什么是账户 以太坊账户与我们所知的账户概念有一定相似之处,却又有很大的区别,更不同于比特币中UTXO. 账户分两类: - 外部拥有账户(EOA),也就是普通账户 - 合约账户 普通账户 所谓的普通账户 ...

随机推荐

  1. 准备新的代码迁移到cnblogs

    http://www.cnblogs.com/danghuijian/ http://www.cnblogs.com/danghuijian/

  2. zoj 2109 FatMouse' Trade

    FatMouse' Trade Time Limit: 2 Seconds      Memory Limit: 65536 KB FatMouse prepared M pounds of cat ...

  3. oracle 9i/10g/11g(11.2.0.3)安装包和PATCH下载地址汇总

    今天上PUB看见一位热心人汇总了这么个地址列表,转发来空间: 把下面的地址复制到讯雷里就可以下载. -------------------------------------------------- ...

  4. c++之析构函数

    #include<iostream>using namespace std;class A{   public:    A(){cout<<"A constructi ...

  5. github新建本地仓库,再同步远程仓库基本用法

    github新建本地仓库,再同步远程仓库基本用法 1 mkdir gitRepo 2 cd gitRepo 3 git init  #初始化本地仓库 4 git add xxx  #添加要push到远 ...

  6. 聪明的猴子(BZOJ 2429)

    题目描述 在一个热带雨林中生存着一群猴子,它们以树上的果子为生.昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上.猴子不会游泳,但跳跃能力比较强,它们仍然可以 ...

  7. Error:Uninitialized object exists on backward branch 70 Exception Details:

    网上下载了一个demo,编译出现如下错误: Gradle sync failed: Uninitialized object exists on backward branch 70 Exceptio ...

  8. ES6__Iterator和for...of循环

    /** * Iterator和for...of循环 */ // --------------------------------------------------------------- /** ...

  9. spring boot 没有主清单属性

  10. [Bzoj4570][Scoi2016]妖怪(右上凸包)

    4570: [Scoi2016]妖怪 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1110  Solved: 336[Submit][Status][ ...