EVM Engine¶
Tags: “EVM” “Smart Contract” “Virtual Machine” “
On the blockchain, users complete actions that require consensus by running contracts deployed on the blockchain。Ethereum virtual machine, the executor of smart contract code。
When the smart contract is compiled into a binary file, it is deployed on the blockchain。The user triggers the execution of the smart contract by calling the interface of the smart contract。The EVM executes the code of the smart contract, modifying the data (state) on the current blockchain。The modified data will be agreed upon to ensure consistency。
EVMC – Ethereum Client-VM Connector API¶
The new version of Ethereum strips the EVM from the node code to form a separate module。The interaction between EVM and node abstracts the EVMC interface standard。Through EVMC, nodes can interface with multiple virtual machines。
The original EVM virtual machine is called interpreter in Ethereum. The following mainly explains the implementation of interpreter。
EVMC Interface¶
EVMC defines two main types of invocation interfaces:
Instance interface: the interface through which the node invokes the EVM
Callback interface: interface of EVM callback node
The EVM itself does not save state data. The node operates the EVM through the instance interface. The EVM, in turn, adjusts the Callback interface to operate the state of the node。

Instance interface
Defines the operation of the node to the virtual machine, including creation, destruction, setup, etc。
The interface is defined in evmc _ instance (evmc.h)
abi_version
name
version
destroy
execute
set_tracer
set_option
Callback Interface
Defines the operations of EVM on nodes, mainly for state reading and writing, block information reading and writing, etc。
The interface is defined in evmc _ context _ fn _ table (evmc.h)。
evmc_account_exists_fn account_exists
evmc_get_storage_fn get_storage
evmc_set_storage_fn set_storage
evmc_get_balance_fn get_balance
evmc_get_code_size_fn get_code_size
evmc_get_code_hash_fn get_code_hash
evmc_copy_code_fn copy_code
evmc_selfdestruct_fn selfdestruct
evmc_call_fn call
evmc_get_tx_context_fn get_tx_context
evmc_get_block_hash_fn get_block_hash
evmc_emit_log_fn emit_log
EVM Execution¶
EVM command¶
Solidity is the execution language of the contract, which is compiled by solc and becomes an assembly-like EVM instruction。Interpreter defines a complete set of instructions。After the solidity is compiled, the binary file is generated, the binary file is the collection of EVM instructions, the transaction is sent to the node in binary form, the node receives, through the EVMC call EVM to execute these instructions。In EVM, the logic of these instructions is implemented in code emulation。
Solidity is a stack-based language, and EVM is called as a stack when executing binary。
Examples of Arithmetic Instruction
An ADD instruction, the code in the EVM is implemented as follows。SP is the pointer of the stack. Take out the data from the first and second positions on the top of the stack (“‘SP [0]”’, “‘SP [1]”’), add and write the data to the top of the result stack SPP “‘SPP [0]”’。
CASE(ADD)
{
ON_OP();
updateIOGas();
// pops two items and pushes their sum mod 2^256.
m_SPP[0] = m_SP[0] + m_SP[1];
}
Jump Instruction Example
JUMP instruction, which implements the jump between binary code。First, from the top of the stack “‘SP [0]”’ take out the address to be jumped, verify whether it is out of bounds, into the program counter PC, the next instruction, will be executed from the position pointed to by the PC。
CASE(JUMP)
{
ON_OP();
updateIOGas();
m_PC = verifyJumpDest(m_SP[0]);
}
Example of Status Read Instruction
SLOAD can query status data。The general procedure is to “SP [0]” from the top of the stack, take the key to be accessed as an argument, and then call the evmc callback function “get _ storage()”’, query the value corresponding to the corresponding key。Then write the read value to the top of the result stack SPP “‘SPP [0]”’。
CASE(SLOAD)
{
m_runGas = m_rev >= EVMC_TANGERINE_WHISTLE ? 200 : 50;
ON_OP();
updateIOGas();
evmc_uint256be key = toEvmC(m_SP[0]);
evmc_uint256be value;
m_context->fn_table->get_storage(&value, m_context, &m_message->destination, &key);
m_SPP[0] = fromEvmC(value);
}
State Write Instruction Example
The SSTORE instruction can write data to the state of the node. The general procedure is to take out key and value from the first and second positions on the top of the stack (“‘SP [0]”’, “‘SP [1]”’), take key and value as parameters, and call evmc’s callback function “‘set _ storage()”’, write the status of the node。
CASE(SSTORE)
{
ON_OP();
if (m_message->flags & EVMC_STATIC)
throwDisallowedStateChange();
static_assert(
VMSchedule::sstoreResetGas <= VMSchedule::sstoreSetGas, "Wrong SSTORE gas costs");
m_runGas = VMSchedule::sstoreResetGas; // Charge the modification cost up front.
updateIOGas();
evmc_uint256be key = toEvmC(m_SP[0]);
evmc_uint256be value = toEvmC(m_SP[1]);
auto status =
m_context->fn_table->set_storage(m_context, &m_message->destination, &key, &value);
if (status == EVMC_STORAGE_ADDED)
{
// Charge additional amount for added storage item.
m_runGas = VMSchedule::sstoreSetGas - VMSchedule::sstoreResetGas;
updateIOGas();
}
}
Examples of contract call instructions
The CALL instruction can call another contract based on the address。First, the EVM determines that it is a CALL instruction and calls “caseCall.”()”’, in caseCall()”’, use”’ caseCallSetup()“‘Take the data from the stack, package it into msg, and call evmc’s callback function as an argument。Eth is called back “()“‘After that, start a new EVM, process the call, and then pass the execution result of the new EVM to” call()“‘parameter is returned to the current EVM, the current EVM writes the result to the result stack SSP, the call ends。The logic for contract creation is similar to this logic。
CASE(CALL)
CASE(CALLCODE)
{
ON_OP();
if (m_OP == Instruction::DELEGATECALL && m_rev < EVMC_HOMESTEAD)
throwBadInstruction();
if (m_OP == Instruction::STATICCALL && m_rev < EVMC_BYZANTIUM)
throwBadInstruction();
if (m_OP == Instruction::CALL && m_message->flags & EVMC_STATIC && m_SP[2] != 0)
throwDisallowedStateChange();
m_bounce = &VM::caseCall;
}
BREAK
void VM::caseCall()
{
m_bounce = &VM::interpretCases;
evmc_message msg = {};
// Clear the return data buffer. This will not free the memory.
m_returnData.clear();
bytesRef output;
if (caseCallSetup(msg, output))
{
evmc_result result;
m_context->fn_table->call(&result, m_context, &msg);
m_returnData.assign(result.output_data, result.output_data + result.output_size);
bytesConstRef{&m_returnData}.copyTo(output);
m_SPP[0] = result.status_code == EVMC_SUCCESS ? 1 : 0;
m_io_gas += result.gas_left;
if (result.release)
result.release(&result);
}
else
{
m_SPP[0] = 0;
m_io_gas += msg.gas;
}
++m_PC;
}
SUMMARY¶
EVM is a state execution machine, the input is the binary instructions compiled by solidity and the state data of the node, and the output is the change of the node state。Ethereum achieves compatibility of multiple virtual machines through EVMC。