How does Ethereum work under the hood? Understanding EVM in Simple English
Table Of Contents
What is an EVM?
Why does understanding EVM matter?
A high-level breakdown of EVM
Global Variables
Persistent Storage
Volatile Storage
Compilation
Accounts in Ethereum
Transactions in Ethereum
Transaction Lifecycle
↳ Success
↳ Failure
Smart Contract Calls
1. Internal calls:
2. External calls:
↳ Call
↳ StaticCall
↳ DelegateCall
The following article is with reference to the course’s smartcontractshacking.com chapter on EVM by Johnny Time.
What is an EVM?
The Ethereum Virtual Machine (EVM) is an essential component of the Ethereum blockchain that executes smart contracts written in programming languages such as Solidity. EVM is a sandboxed environment designed to ensure the secure and deterministic execution of smart contracts. This article provides an overview of the basics of the Ethereum Virtual Machine, including its components and transaction lifecycle.
Why does understanding EVM matter?
- Understanding the technology: EVM is the runtime environment for executing smart contracts in the Ethereum blockchain. By understanding EVM, you can get a deeper understanding of how Ethereum works and how smart contracts are executed.
- Developing smart contracts: If you plan to develop smart contracts for the Ethereum blockchain, you will need to know how EVM works. This includes understanding the programming languages used to write smart contracts (such as Solidity) and how to compile and deploy them to the Ethereum network.
- Security considerations: EVM has its own set of security considerations, such as the potential for reentrancy attacks and integer overflows. By understanding these risks, you can write more secure smart contracts and avoid common vulnerabilities.
- Troubleshooting: If you encounter issues with smart contracts on the Ethereum network, understanding EVM can help you diagnose and resolve the problem.
A high-level breakdown of EVM
The EVM is a virtual machine made up of several components, similar to a virtual machine in our normal computer.
Both EVM and a typical virtual machine in a computer provide an abstraction layer that enables software to be run on different hardware and operating systems without requiring the software to be rewritten for each specific platform. They also both use a set of instructions (opcodes) to perform operations on data, and both have access to memory and storage.
The components of a virtual machine in a normal computer are:
- Hypervisor — The layer that creates and manages the virtual machines
- Virtual CPUs — These emulate the physical CPU of the computer
- Virtual Memory — This is used by the virtual machine to allocate and manage its own memory
- Virtual Devices — These emulate the physical devices of the computer, such as network cards and hard disks
- Virtual Network — This allows the virtual machines to communicate with each other and the outside world
- Management Interface — This is used by the administrator to manage and monitor the virtual machines and their resources
- Virtual Storage — This is used by the virtual machine to access and manage its own storage space, which can be physical or virtual.
In EVM, these are the components of a virtual machine:
Global Variables
Global variables in the EVM include:
- Block Number
- Difficulty
- Transaction Origin: Identifies the original EOA account that sent the transaction.
- Gas Price
Persistent Storage
Persistent storage in the EVM includes:
- Program Code: Stored on the blockchain as bytecode.
- Program Storage: Smart contract storage and state.
- Machine State: Account information that is being updated, such as nonces and balances.
Volatile Storage
Volatile storage in the EVM includes:
- Program Counter: Indicates the number of opcodes being calculated.
- Available Gas: Every transaction is specified gas, and every opcode requires gas. If there is no gas remaining, the transaction is reverted. If there is remaining gas, it is refunded.
- Stack: 32-byte LIFO memory that stores local variables. It has a maximum depth of 1024 and cannot store arrays, mapping structures, or strings.
- Memory: Used to store things that cannot be stored in the stack, such as arrays, mapping structures, and strings.
In the next section, we will be delving into how solidity gets compiled into bytecode which can then be processed by the EVM.
Compilation
The Ethereum Virtual Machine is only capable of understanding bytecode, not programming languages like Solidity.
So how does a high-level language like Solidity gets processed by the EVM then?
Solidity or another high-level language like Vyper firsts needs to be compiled into a series of machine instructions that the EVM can integrate. These instructions are also referred to as “opcodes”. Each Opcode represents a specific operation that the EVM can perform, such as adding 2 numbers or checking the balance of an account.
Once the code has been compiled into opcodes, it is deployed to the Ethereum blockchain. When a user wants to interact with the smart contract, they create a transaction that includes the relevant data and sends it to the network.
When the transaction is processed by the network, the EVM retrieves the bytecode associated with the smart contract and executes it. The EVM reads each opcode in turn and performs the corresponding operation. As the EVM executes the code, it updates the state of the blockchain by modifying account balances or updating contract storage.
At the end of the execution, the EVM returns the output of the smart contract to the user. If the contract modifies the state of the blockchain, the changes will be stored on the Ethereum network for all nodes to see.
So when a smart contract is deployed, only the bytecode is deployed.
How do platforms like Etherscan verify if a contract is valid? The process involves submitting the contract, which Etherscan hashes and compares to the bytecode.
Next, we will touch on how accounts work on Ethereum.
Accounts in Ethereum
Accounts in Ethereum are entities that can send and receive ether, the native cryptocurrency of the Ethereum blockchain.
There are two types of accounts in Ethereum: externally owned accounts (EOAs) and contract accounts.
EOAs are owned by individuals and controlled by private keys. They can send and receive ether (the native cryptocurrency of Ethereum) and interact with smart contracts on the Ethereum network.
Contract accounts, on the other hand, are accounts that store code and are controlled by that code. They can be created by sending a transaction to the Ethereum network with the code to be stored in the account. Once created, the contract account has its own address and can interact with other accounts on the network, including other smart contracts and EOAs.
One main difference between EOAs and smart contract accounts is that EOAs can only send and receive ether, while contract accounts can also execute code and modify their internal state (i.e., storage) based on the logic defined in their smart contract code.
Another key difference is how EOA is able to trigger transactions but the smart contract would not be able to trigger transactions. This is what Account Abstraction (EIP 4337) aim to solve!
Account Abstraction
Currently, every transaction in Ethereum must be initiated and signed by an Externally Owned Account (EOA) with an Ether balance to cover the transaction fee. This means that smart contracts, which do not have a balance, cannot initiate transactions on their own.
Account abstraction proposes to change this by allowing smart contracts to initiate transactions without the need for an EOA. The idea is to abstract the concept of accounts from the underlying blockchain and allow any address, including smart contracts, to initiate transactions.
Account abstraction has the potential to make smart contracts more versatile and powerful, as they can initiate transactions on their own without the need for an EOA. This could open up new use cases for decentralized applications (dApps) and enable new types of interactions between smart contracts and the Ethereum network.
For more details, check out this awesome article explaining EIP 4337 below:
https://blog.jarrodwatts.com/what-is-account-abstraction-and-how-does-eip-4337-work
Transactions in Ethereum
Transactions in Ethereum are messages sent between two accounts in the Ethereum network. They represent a unit of value transfer or the initiation of a smart contract operation. Transactions include information such as the sender and recipient addresses, the amount of Ether or token being transferred, and the gas price and limit for executing the transaction. Transactions are validated and processed by nodes in the network and are recorded on the blockchain as part of a block. Once a transaction is confirmed, its effects are permanent and cannot be reversed.
Transactions are used to activate the Ethereum Virtual Machine. When a transaction is sent, it can contain a message value and message data, which activate the EVM. If ether is sent to a smart contract, it needs a receive()
or fallback()
function; otherwise, the transaction will fail. Data can also be sent to another EOA account or a smart contract.
If a transaction contains data that is to be executed in another smart contract, the EVM will execute the function if the signature is found in the contract; otherwise, it will execute the fallback function. The digram below shows the relationship.
So what are the stages that a transaction in EVM goes through before we see a state change in the blockchain?
Transaction Lifecycle
The lifecycle of a transaction in an Ethereum Virtual Machine (EVM) can be broken down into the following steps:
- Creation: A transaction is created and signed by an external actor, usually an Externally Owned Account (EOA) or a smart contract.
- Propagation: The transaction is propagated through the network of Ethereum nodes until it is picked up by a miner.
- Verification: The miner verifies the transaction’s signature and checks if the account has enough gas to pay for the transaction fee. The node executes every opcode in order, reducing the remaining gas after each opcode is executed. The stack, memory, and storage are updated, and the EVM terminates, wiping the stack and memory.
- Inclusion: The transaction is included in a block, which is then added to the blockchain by the miner.
- Execution: Once the block containing the transaction is added to the blockchain, the transaction is executed by the EVM. The EVM runs the code contained in the smart contract associated with the transaction and updates the state of the Ethereum network accordingly.
- Confirmation: The transaction is considered confirmed once it is included in a block that is deep enough in the blockchain. The number of confirmations required depends on the level of security required for the transaction.
- Completion: The transaction is considered complete once it is confirmed and the smart contract’s code has been executed. The transaction can be queried by external actors to obtain information about its execution status and results.
The Completion phase can either be successful or a failure.
Success
In a successful finish phase:
- Storage and state are updated.
- The remaining gas is refunded.
Failure
In a failed finish phase:
- If there is no gas remaining, the stack and memory are wiped, the transaction is reverted, and there is no gas refund.
- If there is remaining gas, it is refunded after the transaction.
Finally, we will be moving into how smart contract functions are being called in Ethereum.
Smart Contract Calls
There are two types of smart contract calls in Ethereum:
1. Internal calls:
When a contract calls a function within itself, it is called an internal call. The memory and stack remain the same and there is no need for a new EVM instance.
2. External calls:
When a contract calls a function in another contract, it is called an external call. There are three types of external calls:
Call:
The call function is used to call another smart contract and get a response. When the call function is executed, a new EVM instance is created for the target smart contract, which includes the contract code, storage, and a new stack, memory, and program counter. The msg.sender
parameter is set to the address of the invoking smart contract, and the msg.value
parameter is set to the amount specified in the call function.
Once the target smart contract has executed its function, it returns a response to the invoking smart contract. This response might contain data or it might not. If the target smart contract modifies the state of the blockchain, this state change will be reflected in the invoking smart contract’s memory.
StaticCall:
The staticcall function is used to call another smart contract without modifying the state of the blockchain. It is similar to the call function, but with one major difference: it does not allow for state changes to be made to the target contract’s storage or machine state. This is useful for reading data from other smart contracts without incurring the gas costs associated with state changes.
DelegateCall:
This is the most complicated call. There have been many hacks from the insecure use of delegatecall.
The delegatecall function is used to call another smart contract and update the state of the invoking smart contract. In this case, the target smart contract is run with the context of the invoking smart contract, meaning that its memory and stack are set to that of the invoking contract, and its storage is set to that of the invoking contract. The msg.sender
and msg.value
parameters are also set to those of the previous message.
Once the target smart contract has executed its function, any updates it made to the storage of the invoking smart contract will be reflected in the invoking smart contract’s memory. However, the machine state of the invoking smart contract will not be modified, meaning that the gas cost of the operation will be lower than that of a regular call function.
In conclusion, the Ethereum Virtual Machine (EVM) is a crucial component of the Ethereum blockchain that executes smart contracts written in languages such as Solidity. By providing a secure and deterministic sandboxed environment, EVM enables developers to create decentralized applications and smart contracts on the Ethereum network. Understanding EVM is essential for anyone planning to develop smart contracts or troubleshoot issues with them. The EVM consists of several components, including global variables, persistent storage, and volatile sections, which work together to execute smart contracts. By learning about the EVM and how it works, developers can create more secure and efficient smart contracts and contribute to the growth and evolution of the Ethereum network.
Credits to Johnny Time for his breakdown of EVM