Bytecode#
Now that we have the EVM, we can talk a little more about the Bytecode. Bytecode is executed by the EVM.
Valid Bytecode is simply a list of valid opcodes and their operands.
We call a list of opcodes and their operands a program
.
Simple Push#
The program that pushes 0x42
on the stack would look like this.
SIMPLE_PUSH = [0x60, 0x42]
or simply: 0x6042
Instructions and Data#
As you can see, the bytecode consists of both instructions and data. It is up to the program writer to make sure that data and instructions are not mixed up.
This is what we call the von Neumann architecture
.
EVM Versions#
The EVM is not static. It evolves over time through hard forks - coordinated upgrades that add new opcodes or change existing behavior.
Major Ethereum Forks#
Fork |
Date |
Key Changes |
---|---|---|
Frontier |
Jul 2015 |
Original EVM |
Homestead |
Mar 2016 |
Added DELEGATECALL |
Byzantium |
Oct 2017 |
Added REVERT, STATICCALL |
Constantinople |
Feb 2019 |
Added CREATE2, SHL, SHR, SAR |
Istanbul |
Dec 2019 |
Added CHAINID, SELFBALANCE |
London |
Aug 2021 |
Added BASEFEE |
Shanghai |
Apr 2023 |
Added PUSH0 |
Cancun |
Mar 2024 |
Added TLOAD, TSTORE |
Prague |
May 2025 |
Added AUTH, AUTHCALL |
For more up-to-date information, check the Ethereum History page.
Bytecode Compatibility#
Different EVM versions support different opcodes. For example:
PUSH0
(added in Shanghai) creates more efficient bytecode thanPUSH1 0x00
CREATE2
(added in Constantinople) enables deterministic contract addressesTLOAD
/TSTORE
(added in Cancun) provide transient storage
Our mini-EVM implements the Cancun version with all modern opcodes.
Simple Add#
Another simple program could look like this. Here we push 0x42
and 0xFF
on the stack and add them together and put the result back onto the stack.
SIMPLE_ADD = [0x60, 0x42, 0x60, 0xFF, 0x01]
After executing this we should have a stack with exactly one element 321
on it.
In the next step we will use the EVM that we built to actually execute these programs.