py-evm (Python Ethereum Virtual Machine)
Py-EVM is a Python implementation of the Ethereum Virtual Machine (EVM) designed for readability, flexibility for research and experimentation, and performance in testing. It aims to be a reference implementation for the Ethereum execution layer specifications. **As of May 2025, Py-EVM has been archived and is now read-only, with no further development planned. The last supported Ethereum fork is Prague.**
Warnings
- breaking The Py-EVM project has been officially archived and is now read-only. No further development, feature additions, or bug fixes are planned by the maintainers. Users should be aware that the library is no longer actively maintained.
- breaking Py-EVM's last officially supported Ethereum hard fork is Prague. It does not include support for subsequent hard forks, meaning it cannot accurately simulate or interact with the EVM behavior introduced in newer Ethereum versions.
- breaking Version 0.8.0-beta.1 removed external dependencies for Proof-of-Work (like `pyethash`, `pysha3`, and `pycryptodome`) and internalized a less performant `ethash` implementation. This change deprioritized PoW consensus logic within Py-EVM.
- breaking In version 0.3.0-alpha.13, the consensus mechanism abstraction was significantly refactored. `validate_seal` and `validate_header` methods were changed from classmethods to instance methods, and new `ConsensusAPI` and `ConsensusContextAPI` were introduced.
- gotcha Py-EVM is a low-level EVM implementation focused on the execution layer. It does not inherently handle the consensus layer (e.g., Proof of Stake networking, block propagation, or peer-to-peer communication) or direct interaction with live Ethereum networks. It is primarily for local simulation and testing of EVM logic.
Install
-
pip install py-evm
Imports
- MainnetChain
from eth.chains.mainnet import MainnetChain
- AtomicDB
from eth.db.atomic import AtomicDB
- GAS_LIMIT
from eth.constants import GAS_LIMIT
- to_wei
from eth_utils import to_wei
- encode_hex
from eth_utils import encode_hex
- Address
from eth_typing import Address
Quickstart
import os
from eth import constants
from eth.chains.mainnet import MainnetChain
from eth.db.atomic import AtomicDB
from eth_utils import to_wei, encode_hex
from eth_typing import Address
def run_evm_example():
# Setup a mock address and initial balance
MOCK_ADDRESS = Address(b'\x00' * 19 + b'\x01') # An arbitrary address
PREFUND_AMOUNT = to_wei(100, 'ether')
# Initialize a new chain with an atomic database
# AtomicDB is an in-memory database suitable for tests and examples
chain = MainnetChain.from_genesis(
AtomicDB(),
genesis_state={
MOCK_ADDRESS: {
'balance': PREFUND_AMOUNT,
'nonce': 0,
'code': b'',
'storage': {}
}
},
genesis_header_params={
'gas_limit': constants.GAS_LIMIT,
'difficulty': 1 # Simplified difficulty for non-PoW chain
}
)
# Get the current VM from the chain
vm = chain.get_vm()
print(f"Chain created successfully. Current block number: {vm.get_block().header.block_number}")
print(f"Balance of {encode_hex(MOCK_ADDRESS)}: {vm.get_balance(MOCK_ADDRESS)} Wei")
# Example: Accessing a constant
print(f"Default transaction gas limit: {constants.GAS_LIMIT}")
if __name__ == "__main__":
run_evm_example()