The Ethereum Virtual Machine (EVM) : A Complete Overview
The Ethereum Virtual Machine (EVM) is a software execution environment that serves as the core of the Ethereum blockchain network. It provides a isolated sandbox environment where smart contracts can be deployed and executed. The EVM is where all Ethereum accounts and smart contracts live. When you send Ether to someone, interact with a decentralized application, or execute a smart contract, you are interacting with the EVM.
The EVM is a 256-bit virtual machine that is Turing complete, meaning it can execute arbitrary code or computer programs. It was designed to be isolated from the main Ethereum network so that if a smart contract has a bug or gets hacked, it does not affect the overall network. The EVM executes a special binary format known as Ethereum bytecode, which is essentially machine code instructions for the EVM. When a smart contract is compiled, it gets converted to EVM bytecode before being deployed to the network.
All computational execution in Ethereum happens inside the EVM. It acts like a global decentralized computer containing millions of executable objects, each with its own permanent data store. What makes the EVM unique is that each node on the Ethereum network runs a local copy of the EVM to validate transactions and smart contracts. This allows the network to maintain consensus while verifying computations.
The EVM operates as a state machine, where transactions lead to state transitions. Account balances, smart contract data, and other on-chain data are stored in a mutable state that can change with each block. The state transitions depend on the incoming transactions that get executed on the EVM. State changes occur through a series of discrete steps. Because of its deterministic transaction execution, the EVM produces the same result on every node that executes a transaction.
The EVM follows a simple cycle of steps for each block:
- Load the current state: The node loads the state information from the last completed block. This includes account balances, contract storage, etc.
- Validate transactions: Transactions are validated to ensure proper signatures, sufficient balance, etc.
- Execute transactions: The transactions are executed sequentially by the EVM, resulting in changes to contract storage and account balances.
- Generate a receipt: A transaction receipt is generated containing details like the amount of gas used and the address of any new contracts created.
- Calculate total gas used: The total gas used in the block is calculated. Miners are paid the transaction fees based on the gas used.
- Save state: The final state after executing all transactions is saved. This becomes the new current state prepped for the next block.
Some key characteristics of the EVM:
- Isolated environment - Runs in a sandboxed virtual state separated from the main Ethereum state
- State encapsulation - Contract code and data only exist within the EVM
- Deterministic execution - Transactions always result in the same machine state given the same input
- Turing completeness - Can perform arbitrary computation with enough processing time
- Transaction-based - State altered based on sequenced transaction execution
- Programmable - Developers can write and deploy smart contract code to the EVM
The EVM uses a fee-based execution model. All computational tasks have a cost measured in gas. Users must pay the miners this fee to have their transactions included in blocks. This prevents infinite loops, encourages efficiency, and makes denial of service attacks impractical. The gas cost aims to be proportional to the computational resources consumed.
Transactions specify a gas limit and gas price. The total fee paid is gas limit * gas price.
There are two types of accounts in Ethereum - external accounts controlled by private keys and contract accounts controlled by contract code. Both types have an Ether balance and can send transactions. External accounts are accounts owned by users who can send transactions at will. Contract accounts can only send transactions through their coded logic.
When a contract gets deployed, it is assigned a contract account.
Miners are incentivized to include transactions with higher gas prices. The gas price is essentially the bid users make to have their transaction mined. The higher the gas price, the more a user is willing to pay to have the transaction execute promptly. Gas prices adjust based on demand. If the network is congested, gas prices go up as users compete to have their transactions confirmed faster.
The EVM is isolated from the host machine and accounts inside it. No access is allowed to network, filesystem, or other processes. Smart contracts can only touch data within the EVM. This architecture protects users and keeps programs from harming the overall system.
EVM bytecode is a low-level stack-based language with high-level programming features added. It has an instruction set architecture optimized for efficient contract execution. Some examples instructions are:
- Arithmetic (ADD, MUL, etc)
- Cryptographic (SHA3, RIPEMD160, etc)
- Environmental (GAS, BLOCKHASH, etc)
- Stack (POP, DUP, SWAP, etc)
- Memory and storage (MLOAD, MSTORE, SLOAD, etc)
Bytecode gets generated from higher level languages that compile down to EVM instructions. Popular languages for writing Ethereum smart contracts include Solidity, Vyper, and Bamboo.
Here is a simple Solidity contract example:
pragma solidity ^0.8.0; contract Counter { uint public count; constructor() { count = 0; } function increment() public { count += 1; } }
And here is the corresponding EVM bytecode it compiles to:
608060405234801561001057600080fd5b50600160008190555060b9806100276000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063d09de08414602d575b600080fd5b60336047565b604051603e91906064565b60405180910390f35b60025481565b6000819050919050565b605e81604d565b82525050565b6000602082019050607760008301846057565b9291505056fea2646970667358221220109bf23398da4852df246d39ac56fba69e1962ce894a26ea5adf1b7edb97c4c364736f6c634300080f0033
When the contract gets deployed, the EVM bytecode gets embedded into the transaction and stored at the contract's address. Later when the increment function gets called, the EVM will load and execute just the increment portion of the bytecode.
The EVM utilizes a word size of 256-bit to match the 256-bit Ethereum blockchain addresses. All storage reads and writes happen in 32 bytes chunks. Computational costs measured in gas are also priced based on word sizes, with certain operations having a specified gas cost.
The EVM has access to three kinds of space in its isolated environment:
- Stack - volatile space where values are pushed and popped
- Memory - linear volatile space for variable length data
- Storage - key/value store for persisting data between transactions
The stack has a max depth of 1024 elements and is limited to 32 bytes per element. When smart contracts execute, local variables, arguments, and instruction data gets temporarily stored in stack slots.
Memory is an infinitely expandable byte array, but there is a gas cost proportional to the size used. Contract data that needs to exist only temporarily can utilize memory.
Storage is non-volatile and persists for the lifetime of the contract. It is structured as a key/value store implemented as a trie data structure. The KEY is a 256-bit hash used to look up the value contents. Writes to storage have a higher gas cost than reads.
Before execution, smart contracts are loaded by address. Any associated account data like balances as well as storage values persist between executions. Values in memory and stack slots are cleared between each run.
The Ethereum Yellow Paper formally specifies the EVM execution model and opcode specifications. The EVM processes transactions based on this standard to ensure consistent state transitions across clients and implementations.
Major implementations that contain their own EVM include:
- Geth (Go)
- Parity (Rust)
- Trinity (Python)
There are also standalone EVM implementations for testing smart contracts and experimenting with improvements to the EVM itself:
- Cpp-ethereum
- Py-evm
- EVMone
The EVM provides the guarantees needed for Ethereum users to trust the deterministic execution of smart contracts. However, there are still limitations and room for improvement in areas like scalability and transaction speed.
Here are some current limitations and challenges of the EVM architecture:
- All nodes must execute all transactions - limits transaction throughput
- No parallelization of transactions - slows confirmation times
- Storage and computation costs are high - makes some apps economically unfeasible
- Lack of optimization and just-in-time compilation - bytecode not optimized for performance
- No native support for common data structures like hashes and trees
Various solutions are in development to help overcome these limitations:
- Sharding - split network into partitions handling transactions in parallel
- Plasma chains - smaller side chains using fraud proofs to consolidate on the main chain
- Truebit - uses incentive system to verify computations off-chain
- WASM virtual machine - Ethereum may eventually upgrade to a new VM optimized for efficiency
- Rollups - condense transactions from sidechains before appending to main chain
As Ethereum continues evolving, there are sure to be further upgrades and changes to the core EVM architecture and mechanics. The open and transparent nature of Ethereum allows the community to contribute improvements that help scale the platform without sacrificing security or decentralization.
In summary, the Ethereum Virtual Machine is the foundational execution environment that allows decentralized applications and smart contracts to run on the Ethereum blockchain network. Its isolated deterministic nature provides security guarantees that allow the ecosystem to flourish. The EVM continues to be optimized and expanded to support the growth of Ethereum and usher in Web3 innovations.