From a2ed39dae42354a27cbf75fb5108f63a3cf664fb Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 09:29:32 -0400 Subject: [PATCH 01/11] Create EVMC-compatible library --- src/evmc/main.zig | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/evmc/main.zig diff --git a/src/evmc/main.zig b/src/evmc/main.zig new file mode 100644 index 0000000..72e9bad --- /dev/null +++ b/src/evmc/main.zig @@ -0,0 +1,47 @@ +const evmc = @cImport({ + @cInclude("evmc/evmc.h"); +}); + +fn execute( + _: [*c]evmc.evmc_vm, + _: [*c]const evmc.evmc_host_interface, + _: ?*evmc.evmc_host_context, + _: evmc.evmc_revision, + _: [*c]const evmc.evmc_message, + _: [*c]const u8, + _: usize, +) callconv(.C) evmc.evmc_result { + return evmc.evmc_result{ + .status_code = evmc.EVMC_FAILURE, + .gas_left = 0, + .gas_refund = 0, + .output_data = null, + .output_size = 0, + .release = null, + .create_address = evmc.evmc_address{ + .bytes = [20]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + .padding = [4]u8{ 0, 0, 0, 0 }, + }; +} + +fn get_capabilities(_: [*c]evmc.evmc_vm) callconv(.C) evmc.evmc_capabilities_flagset { + return evmc.EVMC_CAPABILITY_EVM1; +} + +fn destroy(_: [*c]evmc.evmc_vm) callconv(.C) void { + return; +} + +export fn evmc_create() callconv(.C) *evmc.evmc_vm { + var vm: evmc.evmc_vm = evmc.evmc_vm{ + .abi_version = evmc.EVMC_ABI_VERSION, + .name = "eth-zvm", + .version = "0.0.1", + .execute = &execute, + .get_capabilities = &get_capabilities, + .set_option = null, + .destroy = &destroy, + }; + return &vm; +} From b1c6c9b38d9d34fc0db6ad0cc06e8166a8f0b605 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 09:33:08 -0400 Subject: [PATCH 02/11] Add build rule for ethzvmlib --- build.zig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build.zig b/build.zig index 1c3b3cd..567a7f1 100644 --- a/build.zig +++ b/build.zig @@ -29,6 +29,15 @@ pub fn build(b: *std.Build) void { mnemonic_exe.addIncludePath(.{ .path = evmc_include_path }); b.installArtifact(mnemonic_exe); + const eth_zvm_lib = b.addSharedLibrary(.{ + .name = "ethzvm", + .root_source_file = .{ .path = "src/evmc/main.zig" }, + .target = target, + .optimize = optimize, + }); + eth_zvm_lib.addIncludePath(.{ .path = evmc_include_path }); + b.installArtifact(eth_zvm_lib); + const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); From 052d426de766400dbd3819e74083aa9fa37b49a5 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 09:33:54 -0400 Subject: [PATCH 03/11] work in progress --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1f90fd2..e5854db 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,7 @@ jobs: - run: name: Run unit tests command: nix develop --command zig build test --summary all + # TODO: Test evmc compatibility of libethzvm. compile_test_cases: executor: nix steps: From dbab667b61b33637bd0d2600a51d7e37c4efb902 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 17:28:16 -0400 Subject: [PATCH 04/11] Move evm logic to evm folder --- src/{ => evm}/memory.zig | 0 src/{ => evm}/stack.zig | 0 src/{ => evm}/vm.zig | 0 src/main.zig | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) rename src/{ => evm}/memory.zig (100%) rename src/{ => evm}/stack.zig (100%) rename src/{ => evm}/vm.zig (100%) diff --git a/src/memory.zig b/src/evm/memory.zig similarity index 100% rename from src/memory.zig rename to src/evm/memory.zig diff --git a/src/stack.zig b/src/evm/stack.zig similarity index 100% rename from src/stack.zig rename to src/evm/stack.zig diff --git a/src/vm.zig b/src/evm/vm.zig similarity index 100% rename from src/vm.zig rename to src/evm/vm.zig diff --git a/src/main.zig b/src/main.zig index ca78694..a3d1068 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const stack = @import("stack.zig"); -const vm = @import("vm.zig"); +const stack = @import("evm/stack.zig"); +const vm = @import("evm/vm.zig"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; From 250162d601cbcbbc69b45497fbcada1bb1648ec4 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 20:37:22 -0400 Subject: [PATCH 05/11] Drop unused import --- src/main.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index a3d1068..9507f94 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const stack = @import("evm/stack.zig"); const vm = @import("evm/vm.zig"); pub fn main() !void { From bbcfc40443940df3b2225818bc56269ea0473293 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 20:57:20 -0400 Subject: [PATCH 06/11] work in progress --- build.zig | 4 +++ src/evm/vm.zig | 90 +++++++++++++++++++++++------------------------ src/evmc/main.zig | 31 ++++++++++++++-- 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/build.zig b/build.zig index 567a7f1..98be8d6 100644 --- a/build.zig +++ b/build.zig @@ -8,6 +8,9 @@ pub fn build(b: *std.Build) void { const evm_module = b.createModule(.{ .source_file = .{ .path = "src/evm/opcodes.zig" }, }); + const evm_vm_module = b.createModule(.{ + .source_file = .{ .path = "src/evm/vm.zig" }, + }); const exe = b.addExecutable(.{ .name = "eth-zvm", @@ -36,6 +39,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); eth_zvm_lib.addIncludePath(.{ .path = evmc_include_path }); + eth_zvm_lib.addModule("evm", evm_vm_module); b.installArtifact(eth_zvm_lib); const run_cmd = b.addRunArtifact(exe); diff --git a/src/evm/vm.zig b/src/evm/vm.zig index cc358a5..3741b4d 100644 --- a/src/evm/vm.zig +++ b/src/evm/vm.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const evm = @import("evm"); const memory = @import("memory.zig"); +const opcodes = @import("opcodes.zig"); const stack = @import("stack.zig"); pub const VMError = error{ @@ -39,7 +39,7 @@ pub const VM = struct { const reader = stream.reader(); - const op: evm.OpCode = reader.readEnum(evm.OpCode, byteOrder) catch |err| switch (err) { + const op: opcodes.OpCode = reader.readEnum(opcodes.OpCode, byteOrder) catch |err| switch (err) { error.EndOfStream => { return false; }, @@ -48,7 +48,7 @@ pub const VM = struct { }, }; switch (op) { - evm.OpCode.ADD => { + opcodes.OpCode.ADD => { std.log.debug("{s}", .{ @tagName(op), }); @@ -59,7 +59,7 @@ pub const VM = struct { self.gasConsumed += 3; return true; }, - evm.OpCode.MOD => { + opcodes.OpCode.MOD => { std.log.debug("{s}", .{@tagName(op)}); self.gasConsumed += 5; const a = try self.stack.pop(); @@ -72,21 +72,21 @@ pub const VM = struct { try self.stack.push(c); return true; }, - evm.OpCode.PUSH1 => { + opcodes.OpCode.PUSH1 => { const b = try reader.readByte(); std.log.debug("{s} 0x{x:0>2}", .{ @tagName(op), b }); try self.stack.push(b); self.gasConsumed += 3; return true; }, - evm.OpCode.PUSH32 => { + opcodes.OpCode.PUSH32 => { const b = try reader.readIntBig(u256); std.log.debug("{s} 0x{x:0>32}", .{ @tagName(op), b }); try self.stack.push(b); self.gasConsumed += 3; return true; }, - evm.OpCode.MSTORE => { + opcodes.OpCode.MSTORE => { std.log.debug("{s}", .{@tagName(op)}); const offset = try self.stack.pop(); const value = try self.stack.pop(); @@ -103,7 +103,7 @@ pub const VM = struct { self.gasConsumed += @as(u64, newState - oldState); return true; }, - evm.OpCode.PC => { + opcodes.OpCode.PC => { std.log.debug("{s}", .{@tagName(op)}); const pos = try stream.getPos(); @@ -112,7 +112,7 @@ pub const VM = struct { return true; }, - evm.OpCode.RETURN => { + opcodes.OpCode.RETURN => { std.log.debug("{s}", .{@tagName(op)}); const offset256 = try self.stack.pop(); const size256 = try self.stack.pop(); @@ -152,9 +152,9 @@ fn testBytecode(bytecode: []const u8, expectedReturnValue: []const u8, expectedG test "add two bytes" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x03, - @intFromEnum(evm.OpCode.PUSH1), 0x02, - @intFromEnum(evm.OpCode.ADD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x03, + @intFromEnum(opcodes.OpCode.PUSH1), 0x02, + @intFromEnum(opcodes.OpCode.ADD), }; // zig fmt: on @@ -165,9 +165,9 @@ test "add two bytes" { test "adding one to max u256 should wrap to zero" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH32), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.ADD), + @intFromEnum(opcodes.OpCode.PUSH32), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.ADD), }; // zig fmt: on @@ -181,9 +181,9 @@ test "adding one to max u256 should wrap to zero" { test "10 modulus 3 is 1" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x03, - @intFromEnum(evm.OpCode.PUSH1), 0x0a, - @intFromEnum(evm.OpCode.MOD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x03, + @intFromEnum(opcodes.OpCode.PUSH1), 0x0a, + @intFromEnum(opcodes.OpCode.MOD), }; // zig fmt: on @@ -197,9 +197,9 @@ test "10 modulus 3 is 1" { test "anything mod 0 is 0" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.PUSH1), 0x05, - @intFromEnum(evm.OpCode.MOD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.PUSH1), 0x05, + @intFromEnum(opcodes.OpCode.MOD), }; // zig fmt: on @@ -213,12 +213,12 @@ test "anything mod 0 is 0" { test "return single-byte value" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x1f, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x1f, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -232,12 +232,12 @@ test "return single-byte value" { test "return 32-byte value" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x20, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x20, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -256,12 +256,12 @@ test "return 32-byte value" { test "use push32 and return a single byte" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH32), 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH32), 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -275,12 +275,12 @@ test "use push32 and return a single byte" { test "use pc to measure program counter" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PUSH1), 0xaa, - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PUSH32), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, - @intFromEnum(evm.OpCode.PC), + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PUSH1), 0xaa, + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PUSH32), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, + @intFromEnum(opcodes.OpCode.PC), }; // zig fmt: on diff --git a/src/evmc/main.zig b/src/evmc/main.zig index 72e9bad..95a35a7 100644 --- a/src/evmc/main.zig +++ b/src/evmc/main.zig @@ -1,3 +1,5 @@ +const std = @import("std"); +const evm = @import("evm"); const evmc = @cImport({ @cInclude("evmc/evmc.h"); }); @@ -8,10 +10,20 @@ fn execute( _: ?*evmc.evmc_host_context, _: evmc.evmc_revision, _: [*c]const evmc.evmc_message, - _: [*c]const u8, - _: usize, + bytecode_c: [*c]const u8, + bytecode_c_size: usize, ) callconv(.C) evmc.evmc_result { - return evmc.evmc_result{ + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + const allocator = gpa.allocator(); + defer _ = gpa.deinit(); + + var vm = evm.VM{}; + vm.init(allocator); + defer vm.deinit(); + + const bytecode = bytecode_c[0..bytecode_c_size]; + + vm.run(bytecode) catch return evmc.evmc_result{ .status_code = evmc.EVMC_FAILURE, .gas_left = 0, .gas_refund = 0, @@ -23,6 +35,19 @@ fn execute( }, .padding = [4]u8{ 0, 0, 0, 0 }, }; + + return evmc.evmc_result{ + .status_code = evmc.EVMC_SUCCESS, + .gas_left = 0, + .gas_refund = 0, + .output_data = null, + .output_size = 0, + .release = null, + .create_address = evmc.evmc_address{ + .bytes = [20]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + }, + .padding = [4]u8{ 0, 0, 0, 0 }, + }; } fn get_capabilities(_: [*c]evmc.evmc_vm) callconv(.C) evmc.evmc_capabilities_flagset { From 952e7cb12a4a3c879aadeb2057d86d9c9c4d32ba Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 20:57:50 -0400 Subject: [PATCH 07/11] Fix import in vm.zig --- src/evm/vm.zig | 90 +++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/evm/vm.zig b/src/evm/vm.zig index cc358a5..3741b4d 100644 --- a/src/evm/vm.zig +++ b/src/evm/vm.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const evm = @import("evm"); const memory = @import("memory.zig"); +const opcodes = @import("opcodes.zig"); const stack = @import("stack.zig"); pub const VMError = error{ @@ -39,7 +39,7 @@ pub const VM = struct { const reader = stream.reader(); - const op: evm.OpCode = reader.readEnum(evm.OpCode, byteOrder) catch |err| switch (err) { + const op: opcodes.OpCode = reader.readEnum(opcodes.OpCode, byteOrder) catch |err| switch (err) { error.EndOfStream => { return false; }, @@ -48,7 +48,7 @@ pub const VM = struct { }, }; switch (op) { - evm.OpCode.ADD => { + opcodes.OpCode.ADD => { std.log.debug("{s}", .{ @tagName(op), }); @@ -59,7 +59,7 @@ pub const VM = struct { self.gasConsumed += 3; return true; }, - evm.OpCode.MOD => { + opcodes.OpCode.MOD => { std.log.debug("{s}", .{@tagName(op)}); self.gasConsumed += 5; const a = try self.stack.pop(); @@ -72,21 +72,21 @@ pub const VM = struct { try self.stack.push(c); return true; }, - evm.OpCode.PUSH1 => { + opcodes.OpCode.PUSH1 => { const b = try reader.readByte(); std.log.debug("{s} 0x{x:0>2}", .{ @tagName(op), b }); try self.stack.push(b); self.gasConsumed += 3; return true; }, - evm.OpCode.PUSH32 => { + opcodes.OpCode.PUSH32 => { const b = try reader.readIntBig(u256); std.log.debug("{s} 0x{x:0>32}", .{ @tagName(op), b }); try self.stack.push(b); self.gasConsumed += 3; return true; }, - evm.OpCode.MSTORE => { + opcodes.OpCode.MSTORE => { std.log.debug("{s}", .{@tagName(op)}); const offset = try self.stack.pop(); const value = try self.stack.pop(); @@ -103,7 +103,7 @@ pub const VM = struct { self.gasConsumed += @as(u64, newState - oldState); return true; }, - evm.OpCode.PC => { + opcodes.OpCode.PC => { std.log.debug("{s}", .{@tagName(op)}); const pos = try stream.getPos(); @@ -112,7 +112,7 @@ pub const VM = struct { return true; }, - evm.OpCode.RETURN => { + opcodes.OpCode.RETURN => { std.log.debug("{s}", .{@tagName(op)}); const offset256 = try self.stack.pop(); const size256 = try self.stack.pop(); @@ -152,9 +152,9 @@ fn testBytecode(bytecode: []const u8, expectedReturnValue: []const u8, expectedG test "add two bytes" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x03, - @intFromEnum(evm.OpCode.PUSH1), 0x02, - @intFromEnum(evm.OpCode.ADD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x03, + @intFromEnum(opcodes.OpCode.PUSH1), 0x02, + @intFromEnum(opcodes.OpCode.ADD), }; // zig fmt: on @@ -165,9 +165,9 @@ test "add two bytes" { test "adding one to max u256 should wrap to zero" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH32), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.ADD), + @intFromEnum(opcodes.OpCode.PUSH32), 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.ADD), }; // zig fmt: on @@ -181,9 +181,9 @@ test "adding one to max u256 should wrap to zero" { test "10 modulus 3 is 1" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x03, - @intFromEnum(evm.OpCode.PUSH1), 0x0a, - @intFromEnum(evm.OpCode.MOD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x03, + @intFromEnum(opcodes.OpCode.PUSH1), 0x0a, + @intFromEnum(opcodes.OpCode.MOD), }; // zig fmt: on @@ -197,9 +197,9 @@ test "10 modulus 3 is 1" { test "anything mod 0 is 0" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.PUSH1), 0x05, - @intFromEnum(evm.OpCode.MOD), + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.PUSH1), 0x05, + @intFromEnum(opcodes.OpCode.MOD), }; // zig fmt: on @@ -213,12 +213,12 @@ test "anything mod 0 is 0" { test "return single-byte value" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x1f, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x1f, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -232,12 +232,12 @@ test "return single-byte value" { test "return 32-byte value" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x20, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x20, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -256,12 +256,12 @@ test "return 32-byte value" { test "use push32 and return a single byte" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PUSH32), 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.MSTORE), - @intFromEnum(evm.OpCode.PUSH1), 0x01, - @intFromEnum(evm.OpCode.PUSH1), 0x00, - @intFromEnum(evm.OpCode.RETURN), + @intFromEnum(opcodes.OpCode.PUSH32), 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.MSTORE), + @intFromEnum(opcodes.OpCode.PUSH1), 0x01, + @intFromEnum(opcodes.OpCode.PUSH1), 0x00, + @intFromEnum(opcodes.OpCode.RETURN), }; // zig fmt: on @@ -275,12 +275,12 @@ test "use push32 and return a single byte" { test "use pc to measure program counter" { // zig fmt: off const bytecode = [_]u8{ - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PUSH1), 0xaa, - @intFromEnum(evm.OpCode.PC), - @intFromEnum(evm.OpCode.PUSH32), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, - @intFromEnum(evm.OpCode.PC), + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PUSH1), 0xaa, + @intFromEnum(opcodes.OpCode.PC), + @intFromEnum(opcodes.OpCode.PUSH32), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, + @intFromEnum(opcodes.OpCode.PC), }; // zig fmt: on From e4450986db8da7b439a72351a971dd438653a14a Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 21:00:30 -0400 Subject: [PATCH 08/11] work in progress --- build.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.zig b/build.zig index 1c3b3cd..575789b 100644 --- a/build.zig +++ b/build.zig @@ -15,7 +15,6 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); - exe.addModule("evm", evm_module); exe.addIncludePath(.{ .path = evmc_include_path }); b.installArtifact(exe); @@ -44,7 +43,6 @@ pub fn build(b: *std.Build) void { .target = target, .optimize = optimize, }); - unit_tests.addModule("evm", evm_module); unit_tests.addIncludePath(.{ .path = evmc_include_path }); const run_unit_tests = b.addRunArtifact(unit_tests); From b5f4680bcf56d7125cd0610637c4655a7bfd2e25 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Sun, 24 Mar 2024 21:03:31 -0400 Subject: [PATCH 09/11] Store binaries as artifacts --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index e5854db..9b5d252 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,6 +60,8 @@ jobs: root: ./ paths: - ./benchmarks/*.benchmark + - store_artifacts: + path: zig-out/ benchmark_evm: executor: base steps: From 74a25fb435ea2f47129d109967ce627af4c608f2 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Fri, 29 Mar 2024 00:20:30 -0400 Subject: [PATCH 10/11] Connect return value --- src/evmc/main.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evmc/main.zig b/src/evmc/main.zig index 95a35a7..fdd67ea 100644 --- a/src/evmc/main.zig +++ b/src/evmc/main.zig @@ -40,8 +40,8 @@ fn execute( .status_code = evmc.EVMC_SUCCESS, .gas_left = 0, .gas_refund = 0, - .output_data = null, - .output_size = 0, + .output_data = vm.returnValue.ptr, + .output_size = vm.returnValue.len, .release = null, .create_address = evmc.evmc_address{ .bytes = [20]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, From 90ccb7397ce3681351ab331c3b76c51a437a6923 Mon Sep 17 00:00:00 2001 From: Michael Lynch Date: Fri, 29 Mar 2024 00:29:50 -0400 Subject: [PATCH 11/11] Use more Zig-native types for pointers --- src/evmc/main.zig | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/evmc/main.zig b/src/evmc/main.zig index fdd67ea..b6227a9 100644 --- a/src/evmc/main.zig +++ b/src/evmc/main.zig @@ -5,11 +5,11 @@ const evmc = @cImport({ }); fn execute( - _: [*c]evmc.evmc_vm, - _: [*c]const evmc.evmc_host_interface, + _: ?*evmc.evmc_vm, + _: ?*const evmc.evmc_host_interface, _: ?*evmc.evmc_host_context, _: evmc.evmc_revision, - _: [*c]const evmc.evmc_message, + _: ?*const evmc.evmc_message, bytecode_c: [*c]const u8, bytecode_c_size: usize, ) callconv(.C) evmc.evmc_result { @@ -21,9 +21,7 @@ fn execute( vm.init(allocator); defer vm.deinit(); - const bytecode = bytecode_c[0..bytecode_c_size]; - - vm.run(bytecode) catch return evmc.evmc_result{ + const fail_result = evmc.evmc_result{ .status_code = evmc.EVMC_FAILURE, .gas_left = 0, .gas_refund = 0, @@ -36,6 +34,10 @@ fn execute( .padding = [4]u8{ 0, 0, 0, 0 }, }; + const bytecode = bytecode_c[0..bytecode_c_size]; + + vm.run(bytecode) catch return fail_result; + return evmc.evmc_result{ .status_code = evmc.EVMC_SUCCESS, .gas_left = 0, @@ -50,11 +52,11 @@ fn execute( }; } -fn get_capabilities(_: [*c]evmc.evmc_vm) callconv(.C) evmc.evmc_capabilities_flagset { +fn get_capabilities(_: ?*evmc.evmc_vm) callconv(.C) evmc.evmc_capabilities_flagset { return evmc.EVMC_CAPABILITY_EVM1; } -fn destroy(_: [*c]evmc.evmc_vm) callconv(.C) void { +fn destroy(_: ?*evmc.evmc_vm) callconv(.C) void { return; }