An Ethereum Virtual Machine (EVM) implementation from scratch, written in Go.
Warning
This implementation is for educational purposes and not for production use.
This project is an isolated EVM implementation, meaning it has no state for accounts. However, memory, storage, and event logs are tracked, although everything resets after each EVM execution.
- The Go programming language should be installed: https://go.dev/dl/
- Ethereum Virtual Machine: https://ethereum.org/en/developers/docs/evm/
- EVM opcodes: https://www.evm.codes/
To run the EVM:
Navigate to the command directory:
cd cmd/gevmExecute the main program:
go run main.go
Some simple example bytecodes are provided. There is also an example from an actual compiled contract, which is commented out. Uncomment it to run it.

Dynamic gas calculation is supported (memory expansion cost and storage operations). Functions for this are located in gevm/common.go, and the dgMap[Opcode]uint64 in gevm/evm.go holds records of each opcode that has dynamic gas. The dynamic gas is calculated at runtime for any opcode that has dynamic gas during execution, and the dgMap is updated to store this gas cost.
The main EVM files are located in /gevm. Here are some key structures:
ExecutionRuntimerepresents the execution runtime during EVM execution.typeExecutionRuntimestruct { PCuint64Code []byteGasuint64Refunduint64StopFlagboolRevertFlagboolReturnData []byteLogRecord*LogRecordBlock*Block }
ExecutionEnvironmentencapsulates the EVM execution data environment, including the stack, memory, storage, and transient storage.typeExecutionEnvironmentstruct { Stack*StackMemory*MemoryStorage*StorageTransient*TransientStorage }
TransactionContextholds transaction-specific information during EVM execution.typeTransactionContextstruct { Sender common.AddressValueuint64Calldata []byte }
ChainConfigstores network configuration parameters.typeChainConfigstruct { ChainIDuint64GasLimituint64 }
Blockrepresents a block.typeBlockstruct { Coinbase common.AddressGasPriceuint64Numberuint64Timestamp time.TimeBaseFeeuint64 }
All these are initialized with the NewEVM function found in gevm/evm.go.
To run unit tests:
go test -vFor a better understanding of the project, explore the files in /gevm.
The implementation supports 131 out of the 143 EVM opcodes.
The following opcodes are not supported:
- CREATE
- CALL
- CALLCODE
- DELEGATECALL
- CREATE2
- EXTCODEHASH
- DIFFICULTY
- STATICCALL
- SELFBALANCE
- SELFDESTRUCT
- EIP-4844 opcodes: BLOBHASH, BLOBBASEFEE
These opcodes typically require state management. All other opcodes are supported, including EIP-1153 transient storage opcodes TLOAD and TSTORE.
- EVM opcodes (highly recommended, has accurate gas costs for opcodes): https://www.evm.codes/
- EVM from scratch book: https://evm-from-scratch.xyz/
Contributions are welcome! Please feel free to create an issue or submit a pull request.