Skip to content
omerfirmakPublic

About

Zig EVM - Ethereum protocol in Zig

Topics

Resources

Stars

20 stars

Watchers

0 watching

Forks

Latest commit

 

History

671 Commits

Folders and files

Repository files navigation

image

An alpha EVM implementation in Zig, using threaded code dispatch for opcode execution.

Requirements

  • Zig 0.16.0

Building

zig build

Running tests

Run unit tests:

zig build test

Run the full state test suite after fetching the fixture archive and extracting it:

zig build state-tests

Run a single fixture file:

zig build state-tests -Dstate-test=/path/to/fixture.json

Usage

The entry point for executing a transaction is EVM.init followed by EVM.process. You need to provide a Message (transaction parameters), a Context (block parameters), and a State (account/storage world state).

See example/main.zig for a working end-to-end example (zig build example to run it).

CommittedState

The EVM reads account balances, storage slots, and contract code through a CommittedState interface. Consumers provide their own implementation to back these reads with a real database, in-memory map, or anything else.

A CommittedState must be a struct exposing the same methods as the default implementation in src/evm/committed_state.zig. See example/committed_state.zig for a working consumer-side example.

Using zevm as a dependency

Add zevm to your build.zig.zon:

.zevm = .{
    .url = "git+https://github.com/omerfirmak/zevm.git#<commit>",
    .hash = "<hash>",
},

If you only need to execute against a zero world state — no real account balances, storage, or code — wire zevm directly:

const zevm_dep = b.dependency("zevm", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("zevm", zevm_dep.module("zevm"));

The default committed_state_impl = .empty selects the built-in empty implementation: account/storage reads return zero, code lookups return error.NotFound.

To back zevm with a real database / in-memory map / anything else, opt into .external and wire your own implementation module:

const zevm_dep = b.dependency("zevm", .{
    .target = target,
    .optimize = optimize,
    .committed_state_impl = .external,
});
const zevm_mod = zevm_dep.module("zevm");

// Your CommittedState implementation. It can `@import("zevm")` to use
// `types.Account`, `types.StorageLookup`, `Trie`, etc.
const cs_mod = b.createModule(.{
    .root_source_file = b.path("src/my_committed_state.zig"),
    .target = target,
    .optimize = optimize,
});
cs_mod.addImport("zevm", zevm_mod);
zevm_mod.addImport("committed_state", cs_mod);

exe.root_module.addImport("zevm", zevm_mod);

The two addImport calls form an intentional cycle — zevm imports your committed_state, and your committed_state file gets a "zevm" import to use back. This lets your implementation reference zevm types without you having to redeclare them.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

Zig EVM - Ethereum protocol in Zig

Topics

Resources

Stars

20 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages