Pre:
每处理一笔交易,就要新建一个 EVM对象
来执行交易中的数据。
这是在执行交易的入口 ApplyTransaction
函数中体现的:
1 | func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { |
以太坊虚拟机EVM:
evm 模块的核心对象是 EVM,它代表了一个以太坊虚拟机,用于创建或调用某个合约。
EVM 对象内部主要依赖三个对象:
-
解释器
Interpreter
-
虚拟机相关配置对象
vm.Config
-
以太坊状态数据库
StateDB
这3个对象后面会一一介绍,先看看EVM对象本身的源码。
EVM数据结构:
1 | type EVM struct { |
创建EVM
对象需要依赖以下信息:
-
BlockContext
: 区块相关信息 -
TxContext
: 交易相关信息 -
chainConfig
:链配置信息 -
chainRules
:链规则 -
Config
:虚拟机解释器配置信息 -
interpreter
:EVM 解释器
需要记录以下信息:
-
depth
: 记录当前调用的栈的深度 -
abort
: 用于中止EVM调用操作 -
callGasTemp
: 当前call可用的gas
创建EVM所需信息:
BlockContext 区块信息:
其中BlockContext
里包含了区块的相关信息,例如当前区块的矿工地址、当前区块号等
1 | // BlockContext provides the EVM with auxiliary information. Once provided |
TxContext 交易信息:
其中TxContext
里包含了交易的相关信息:交易发起者、 交易的gas价格
1 | // TxContext provides the EVM with information about a transaction. |
区块信息和交易信息在solidity文档的区块和交易属性有列举出来:
区块信息:
-
blockhash(uint blockNumber) returns (bytes32)
:指定区块的区块哈希 —— 仅可用于最新的 256 个区块且不包括当前区块,否则返回 0 。 -
block.basefee (uint)
: 当前区块的基础费用,参考: (EIP-3198 和 EIP-1559) -
block.chainid (uint)
: 当前链 id -
block.coinbase ( address )
: 挖出当前区块的矿工地址 -
block.difficulty ( uint )
: 当前区块难度 -
block.gaslimit ( uint )
: 当前区块 gas 限额 -
block.number ( uint )
: 当前区块号 -
block.timestamp ( uint)
: 自 unix epoch 起始当前区块以秒计的时间戳
交易信息:
-
tx.gasprice (uint)
: 交易的 gas 价格 -
tx.origin ( address )
: 交易发起者(完全的调用链) -
msg.data ( bytes )
: 完整的 calldata -
msg.sender ( address )
: 消息发送者(当前调用) -
msg.sig ( bytes4 )
: calldata 的前 4 字节(也就是函数标识符) -
msg.value ( uint )
: 随消息发送的 wei 的数量
chainConfig 链配置信息
1 | type ChainConfig struct { |
chainRules 链规则:
1 | // Rules ensures c's ChainID is not nil. |
返回chainConfig
里属性的布尔值
Config 解释器配置信息:
1 | // Config are the configuration options for the Interpreter |
比较重要的属性是JumpTable
操作码opcode对应的操作表
创建EVM函数:
1 | func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { |
NewEVM()
函数用来创建一个新的虚拟机对象,它有5个参数,含义分别如下:
-
blockCtx
: 区块的信息和挖矿环境的函数和数据 -
txCtx
: 交易的信息 -
statedb
: 以太坊状态数据库对象 -
chainConfig
: 当前节点的区块链配置信息 -
config
: 虚拟机配置信息
NewEVM()
函数的实现,除了把参数记录下来以外,主要就是调用 NewEVMInterpreter()
创建一个解释器对象。
后面另外介绍 EVM的解释器对象
小结:
-
以太坊在每处理一笔交易时,都会新建一个 EVM 对象来处理。
-
创建一个EVM对象需要依赖以下信息:
BlockContext
: 区块相关信息TxContext
: 交易相关信息chainConfig
:链配置信息chainRules
:链规则Config
:虚拟机解释器配置信息interpreter
:EVM 解释器
-
需要记录以下信息:
depth
: 记录当前调用的栈的深度abort
: 用于中止EVM调用操作callGasTemp
: 当前call可用的gas