Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
389 changes: 389 additions & 0 deletions bench/evm/precompiles_bench.zig

Large diffs are not rendered by default.

71 changes: 70 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,23 @@ pub fn build(b: *std.Build) void {
});
compiler_mod.addImport("zabi", zabi_dep.module("zabi"));

const precompiles_mod = b.createModule(.{
.root_source_file = b.path("src/precompiles/package.zig"),
.target = target,
.optimize = optimize,
});
precompiles_mod.stack_check = false;
precompiles_mod.single_threaded = true;

// Create WASM-specific precompiles module with C API
const precompiles_wasm_mod = b.createModule(.{
.root_source_file = b.path("src/precompiles/wasm_c_api.zig"),
.target = wasm_target,
.optimize = .ReleaseSmall,
});
precompiles_wasm_mod.stack_check = false;
precompiles_wasm_mod.single_threaded = true;

// Create a separate compiler module for WASM without problematic dependencies
const compiler_wasm_mod = b.createModule(.{
.root_source_file = b.path("src/compilers/compiler_wasm.zig"),
Expand Down Expand Up @@ -153,6 +170,7 @@ pub fn build(b: *std.Build) void {
evm_mod.addImport("Address", address_mod);
evm_mod.addImport("Block", block_mod);
evm_mod.addImport("Rlp", rlp_mod);
evm_mod.addImport("precompiles", precompiles_mod);

// Create a ZigEVM module - our core EVM implementation
const target_architecture_mod = b.createModule(.{
Expand All @@ -171,6 +189,7 @@ pub fn build(b: *std.Build) void {
target_architecture_mod.addImport("Block", block_mod);
target_architecture_mod.addImport("Bytecode", bytecode_mod);
target_architecture_mod.addImport("Compiler", compiler_mod);
target_architecture_mod.addImport("Precompiles", precompiles_mod);
target_architecture_mod.addImport("evm", evm_mod);
target_architecture_mod.addImport("Rlp", rlp_mod);
target_architecture_mod.addImport("Token", token_mod);
Expand Down Expand Up @@ -241,10 +260,23 @@ pub fn build(b: *std.Build) void {
const wasm_output_path = "dist/zigevm.wasm";
const install_wasm = b.addInstallFile(wasm.getEmittedBin(), wasm_output_path);

// Create the Precompiles WebAssembly library
const precompiles_wasm_lib = b.addExecutable(.{
.name = "tevm-precompiles",
.root_module = precompiles_wasm_mod,
});
precompiles_wasm_lib.rdynamic = true; // Required for exported functions
precompiles_wasm_lib.entry = .disabled; // No entry point for library mode

Comment on lines +263 to +270
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

tevm-precompiles is built for the host, not wasm32

addExecutable inherits the build-target when .target is omitted, ignoring the wasm_target you defined.

As a result the produced artifact is a native binary named *.wasm, breaking downstream tooling and the size claims in the report.

 const precompiles_wasm_lib = b.addExecutable(.{
     .name = "tevm-precompiles",
     .root_module = precompiles_wasm_mod,
+    .target = wasm_target,
+    .optimize = .ReleaseSmall,
 });

Please verify the emitted file with file dist/tevm-precompiles.wasm after the fix – it should report WebAssembly (wasm).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Create the Precompiles WebAssembly library
const precompiles_wasm_lib = b.addExecutable(.{
.name = "tevm-precompiles",
.root_module = precompiles_wasm_mod,
});
precompiles_wasm_lib.rdynamic = true; // Required for exported functions
precompiles_wasm_lib.entry = .disabled; // No entry point for library mode
// Create the Precompiles WebAssembly library
const precompiles_wasm_lib = b.addExecutable(.{
.name = "tevm-precompiles",
.root_module = precompiles_wasm_mod,
.target = wasm_target,
.optimize = .ReleaseSmall,
});
precompiles_wasm_lib.rdynamic = true; // Required for exported functions
precompiles_wasm_lib.entry = .disabled; // No entry point for library mode
🤖 Prompt for AI Agents
In build.zig around lines 263 to 270, the tevm-precompiles executable is
incorrectly built for the host target instead of the wasm32 target because the
.target field is missing in the addExecutable call. To fix this, explicitly set
the .target field to wasm_target when creating precompiles_wasm_lib so it builds
for the correct WebAssembly target. After the fix, verify the output file with
the file command to ensure it is a WebAssembly binary.

// Define the precompiles WASM output path
const precompiles_wasm_output_path = "dist/tevm-precompiles.wasm";
const install_precompiles_wasm = b.addInstallFile(precompiles_wasm_lib.getEmittedBin(), precompiles_wasm_output_path);

// Install all artifacts
b.installArtifact(lib);
b.installArtifact(exe);
b.installArtifact(wasm);
b.installArtifact(precompiles_wasm_lib);
b.installArtifact(server_exe);
b.installArtifact(ui_exe);

Expand All @@ -265,6 +297,10 @@ pub fn build(b: *std.Build) void {
const build_wasm_step = b.step("wasm", "Build the WebAssembly artifact");
build_wasm_step.dependOn(&install_wasm.step);

// Build Precompiles WASM step
const build_precompiles_wasm_step = b.step("wasm-precompiles", "Build the Precompiles WebAssembly library");
build_precompiles_wasm_step.dependOn(&install_precompiles_wasm.step);

// Define a run server step
const run_server_cmd = b.addRunArtifact(server_exe);
run_server_cmd.step.dependOn(b.getInstallStep());
Expand Down Expand Up @@ -298,6 +334,7 @@ pub fn build(b: *std.Build) void {
lib_unit_tests.root_module.addImport("Block", block_mod);
lib_unit_tests.root_module.addImport("Bytecode", bytecode_mod);
lib_unit_tests.root_module.addImport("Compiler", compiler_mod);
lib_unit_tests.root_module.addImport("Precompiles", precompiles_mod);
lib_unit_tests.root_module.addImport("evm", evm_mod);
lib_unit_tests.root_module.addImport("Rlp", rlp_mod);
lib_unit_tests.root_module.addImport("Token", token_mod);
Expand All @@ -321,6 +358,7 @@ pub fn build(b: *std.Build) void {
evm_test.root_module.addImport("Bytecode", bytecode_mod);
evm_test.root_module.addImport("Compiler", compiler_mod);
evm_test.root_module.addImport("evm", evm_mod);
evm_test.root_module.addImport("precompiles", precompiles_mod);
evm_test.root_module.addImport("Rlp", rlp_mod);
evm_test.root_module.addImport("Token", token_mod);
evm_test.root_module.addImport("Trie", trie_mod);
Expand Down Expand Up @@ -790,11 +828,26 @@ pub fn build(b: *std.Build) void {
const evm_memory_benchmark_step = b.step("bench-evm-memory", "Run EVM Memory benchmarks");
evm_memory_benchmark_step.dependOn(&run_evm_memory_benchmark.step);

// Add EVM Precompiles benchmark (defined later to access rust step)
const evm_precompiles_benchmark = b.addExecutable(.{
.name = "evm-precompiles-benchmark",
.root_source_file = b.path("bench/evm/precompiles_bench.zig"),
.target = target,
.optimize = .ReleaseFast,
});
evm_precompiles_benchmark.root_module.addImport("zbench", zbench_dep.module("zbench"));
evm_precompiles_benchmark.root_module.addImport("Precompiles", precompiles_mod);

const run_evm_precompiles_benchmark = b.addRunArtifact(evm_precompiles_benchmark);

const evm_precompiles_benchmark_step = b.step("bench-evm-precompiles", "Run EVM Precompiles benchmarks");
evm_precompiles_benchmark_step.dependOn(&run_evm_precompiles_benchmark.step);

// Add combined benchmark step
const all_benchmark_step = b.step("bench", "Run all benchmarks");
all_benchmark_step.dependOn(&run_memory_benchmark.step);
all_benchmark_step.dependOn(&run_evm_memory_benchmark.step);
all_benchmark_step.dependOn(&run_evm_memory_benchmark.step);
all_benchmark_step.dependOn(&run_evm_precompiles_benchmark.step);

// Add Rust Foundry wrapper integration
const rust_build = @import("src/compilers/rust_build.zig");
Expand All @@ -803,6 +856,13 @@ pub fn build(b: *std.Build) void {
return;
};

// Add Rust Precompiles wrapper integration
const precompiles_rust_build = @import("src/precompiles/rust_build.zig");
const precompiles_rust_step = precompiles_rust_build.add_rust_integration(b, target, optimize) catch |err| {
std.debug.print("Failed to add Rust precompiles integration: {}\n", .{err});
return;
};

// Make the compiler test depend on the Rust build
compiler_test.step.dependOn(rust_step);

Expand All @@ -821,6 +881,15 @@ pub fn build(b: *std.Build) void {
// compiler_test.linkFramework("SystemConfiguration");
}

// Make the precompiles benchmark depend on the Rust precompiles build
evm_precompiles_benchmark.step.dependOn(precompiles_rust_step);

// Link the Rust precompiles library to the benchmark
precompiles_rust_build.link_precompiles(evm_precompiles_benchmark, b);

// Add include path to precompiles module after Rust build
precompiles_mod.addIncludePath(b.path("zig-out/include"));

const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

const exe_unit_tests = b.addTest(.{
Expand Down
26 changes: 18 additions & 8 deletions src/evm/evm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,27 @@ pub const MemoryDatabase = @import("state/memory_database.zig").MemoryDatabase;
pub const DatabaseFactory = @import("state/database_factory.zig");

/// Precompiled contracts implementation (IDENTITY, SHA256, etc.)
pub const Precompiles = @import("precompiles/precompiles.zig");
/// Using the new comprehensive precompiles package with hybrid REVM/Zig approach
pub const Precompiles = @import("precompiles").Precompiles;

/// Precompiles namespace for easier access
pub const precompiles = struct {
pub const precompiles = @import("precompiles/precompiles.zig");
pub const identity = @import("precompiles/identity.zig");
pub const sha256 = @import("precompiles/sha256.zig");
pub const ripemd160 = @import("precompiles/ripemd160.zig");
pub const precompile_result = @import("precompiles/precompile_result.zig");
pub const PrecompileOutput = @import("precompiles/precompile_result.zig").PrecompileOutput;
pub const PrecompileError = @import("precompiles/precompile_result.zig").PrecompileError;
pub const Precompiles = @import("precompiles").Precompiles;
pub const PrecompileResult = @import("precompiles").PrecompileResult;
pub const PrecompileError = @import("precompiles").PrecompileError;
pub const PrecompileType = @import("precompiles").PrecompileType;

// Convenience functions
pub const sha256 = @import("precompiles").sha256;
pub const identity = @import("precompiles").identity;
pub const ecrecover = @import("precompiles").ecrecover;
pub const ripemd160 = @import("precompiles").ripemd160;
pub const modexp = @import("precompiles").modexp;
pub const blake2f = @import("precompiles").blake2f;

// Compatibility aliases
pub const precompiles = @import("precompiles").precompiles;
pub const PrecompileOutput = @import("precompiles").PrecompileOutput; // Alias for compatibility
};

/// EIP-4844 blob transaction support (blobs, KZG verification, gas market)
Expand Down
2 changes: 1 addition & 1 deletion src/evm/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub const CreateResult = @import("create_result.zig").CreateResult;
pub const CallResult = @import("call_result.zig").CallResult;
pub const RunResult = @import("run_result.zig").RunResult;
const Hardfork = @import("hardforks/hardfork.zig").Hardfork;
const precompiles = @import("precompiles/precompiles.zig");
const precompiles = @import("precompiles");

/// Virtual Machine for executing Ethereum bytecode.
///
Expand Down
Loading
Loading