From 1f8b9699a4a0705720d2ed5f90e878efecf9181f Mon Sep 17 00:00:00 2001 From: bing Date: Wed, 29 Oct 2025 19:03:41 +0800 Subject: [PATCH 1/5] chore: remove `hex` Most of the utils in `hex.zig` are not being used, and what's left of those used ones (2 of them) are only used in `config` and `test_utils`, so we might as well put them where they're used. This alsos simplifies imports/dependencies for consumer libraries. --- build.zig | 2 - src/config/chain/networks/chiado.zig | 3 +- src/config/chain/networks/gnosis.zig | 3 +- src/config/chain/networks/hoodi.zig | 3 +- src/config/chain/networks/mainnet.zig | 3 +- src/config/chain/networks/minimal.zig | 3 +- src/config/chain/networks/sepolia.zig | 3 +- src/config/root.zig | 10 ++ src/hex.zig | 95 ------------------- .../test_utils/generate_block.zig | 4 +- .../test_utils/generate_state.zig | 23 ++--- src/state_transition/test_utils/root.zig | 16 ++++ zbuild.zon | 3 +- 13 files changed, 47 insertions(+), 124 deletions(-) delete mode 100644 src/hex.zig diff --git a/build.zig b/build.zig index b99c5f6b..acdbb2a4 100644 --- a/build.zig +++ b/build.zig @@ -695,7 +695,6 @@ pub fn build(b: *std.Build) void { module_config.addImport("build_options", options_module_build_options); module_config.addImport("preset", module_preset); module_config.addImport("consensus_types", module_consensus_types); - module_config.addImport("hex", module_hex); module_config.addImport("constants", module_constants); module_consensus_types.addImport("build_options", options_module_build_options); @@ -726,7 +725,6 @@ pub fn build(b: *std.Build) void { module_state_transition.addImport("blst", dep_blst.module("blst")); module_state_transition.addImport("preset", module_preset); module_state_transition.addImport("constants", module_constants); - module_state_transition.addImport("hex", module_hex); module_download_spec_tests.addImport("spec_test_options", options_module_spec_test_options); diff --git a/src/config/chain/networks/chiado.zig b/src/config/chain/networks/chiado.zig index 6ebf8e43..edfa909c 100644 --- a/src/config/chain/networks/chiado.zig +++ b/src/config/chain/networks/chiado.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const Preset = @import("preset").Preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; const gnosis = @import("./gnosis.zig").gnosis_chain_config; diff --git a/src/config/chain/networks/gnosis.zig b/src/config/chain/networks/gnosis.zig index 7975038e..9e8aaeab 100644 --- a/src/config/chain/networks/gnosis.zig +++ b/src/config/chain/networks/gnosis.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const Preset = @import("preset").Preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; pub const gnosis_chain_config = ChainConfig{ .PRESET_BASE = Preset.gnosis, diff --git a/src/config/chain/networks/hoodi.zig b/src/config/chain/networks/hoodi.zig index b5deadaa..04f1c484 100644 --- a/src/config/chain/networks/hoodi.zig +++ b/src/config/chain/networks/hoodi.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const preset = @import("preset").preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; const mainnet = @import("./mainnet.zig").mainnet_chain_config; diff --git a/src/config/chain/networks/mainnet.zig b/src/config/chain/networks/mainnet.zig index 53b37479..6a3c9990 100644 --- a/src/config/chain/networks/mainnet.zig +++ b/src/config/chain/networks/mainnet.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const Preset = @import("preset").Preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; pub const mainnet_chain_config = ChainConfig{ .PRESET_BASE = Preset.mainnet, diff --git a/src/config/chain/networks/minimal.zig b/src/config/chain/networks/minimal.zig index f3b285dc..165e431e 100644 --- a/src/config/chain/networks/minimal.zig +++ b/src/config/chain/networks/minimal.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const Preset = @import("preset").Preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; pub const minimal_chain_config = ChainConfig{ .PRESET_BASE = Preset.minimal, diff --git a/src/config/chain/networks/sepolia.zig b/src/config/chain/networks/sepolia.zig index 2b5b8342..e069308b 100644 --- a/src/config/chain/networks/sepolia.zig +++ b/src/config/chain/networks/sepolia.zig @@ -1,9 +1,8 @@ const std = @import("std"); -const hex_utils = @import("hex"); const preset = @import("preset").preset; const ChainConfig = @import("../chain_config.zig").ChainConfig; const BlobScheduleEntry = @import("../chain_config.zig").BlobScheduleEntry; -const b = hex_utils.hexToBytesComptime; +const b = @import("../../root.zig").hexToBytesComptime; const mainnet = @import("./mainnet.zig").mainnet_chain_config; diff --git a/src/config/root.zig b/src/config/root.zig index 7d3c88f6..65db6d6a 100644 --- a/src/config/root.zig +++ b/src/config/root.zig @@ -14,6 +14,16 @@ pub const chiado_chain_config = @import("./chain/networks/chiado.zig").chiado_ch pub const sepolia_chain_config = @import("./chain/networks/sepolia.zig").sepolia_chain_config; pub const hoodi_chain_config = @import("./chain/networks/hoodi.zig").hoodi_chain_config; +pub fn hexToBytesComptime(comptime n: usize, comptime input: []const u8) [n]u8 { + var out: [n]u8 = undefined; + if (input[0] == '0' and input[1] == 'x') { + _ = std.fmt.hexToBytes(&out, input[2..]) catch unreachable; + } else { + _ = std.fmt.hexToBytes(&out, input) catch unreachable; + } + return out; +} + test { testing.refAllDecls(@This()); } diff --git a/src/hex.zig b/src/hex.zig deleted file mode 100644 index 7df45c7d..00000000 --- a/src/hex.zig +++ /dev/null @@ -1,95 +0,0 @@ -const std = @import("std"); -const fmt = std.fmt; - -pub fn hexToBytesComptime(comptime n: usize, comptime input: []const u8) [n]u8 { - var out: [n]u8 = undefined; - _ = hexToBytes(out[0..], input) catch unreachable; - return out; -} - -/// Convert hex to bytes with 0x-prefix support -pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 { - if (hasOxPrefix(input)) { - return try fmt.hexToBytes(out, input[2..]); - } else { - return try fmt.hexToBytes(out, input); - } -} - -/// Convert bytes to hex with 0x-prefix -pub fn bytesToHex(out: []u8, input: []const u8) ![]u8 { - return try fmt.bufPrint(out, "0x{x}", .{fmt.fmtSliceHexLower(input)}); -} - -pub fn hexToRoot(input: *const [66]u8) ![32]u8 { - var out: [32]u8 = undefined; - _ = try hexToBytes(&out, input); - return out; -} - -pub fn hexIntoRoot(out: *[32]u8, input: *const [66]u8) !void { - _ = try hexToBytes(out, input); -} - -pub fn rootToHex(input: *const [32]u8) ![66]u8 { - var out: [66]u8 = undefined; - _ = try bytesToHex(&out, input); - return out; -} - -pub fn rootIntoHex(out: *[66]u8, input: *const [32]u8) !void { - _ = try bytesToHex(out, input); -} - -pub fn hasOxPrefix(hex: []const u8) bool { - return hex[0] == '0' and hex[1] == 'x'; -} - -pub fn hexByteLen(hex: []const u8) usize { - return if (hasOxPrefix(hex)) (hex.len - 2) / 2 else hex.len / 2; -} - -pub fn hexLenFromBytes(bytes: []const u8) usize { - return 2 + bytes.len * 2; -} - -test "rootToHex" { - const TestCase = struct { - root: *const [32]u8, - expected: []const u8, - }; - - const test_cases = [_]TestCase{ - TestCase{ .root = &[_]u8{0} ** 32, .expected = "0x0000000000000000000000000000000000000000000000000000000000000000" }, - TestCase{ .root = &[_]u8{10} ** 32, .expected = "0x0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a" }, - TestCase{ .root = &[_]u8{17} ** 32, .expected = "0x1111111111111111111111111111111111111111111111111111111111111111" }, - TestCase{ .root = &[_]u8{255} ** 32, .expected = "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" }, - }; - - for (test_cases) |tc| { - const hex = try rootToHex(tc.root); - try std.testing.expectEqualSlices(u8, tc.expected, &hex); - } -} - -test "hexToBytes" { - const TestCase = struct { - hex: []const u8, - expected: []const u8, - }; - - const test_cases = [_]TestCase{ - TestCase{ .hex = "00000000", .expected = &[_]u8{ 0, 0, 0, 0 } }, - TestCase{ .hex = "c78009fd", .expected = &[_]u8{ 199, 128, 9, 253 } }, - TestCase{ .hex = "C78009FD", .expected = &[_]u8{ 199, 128, 9, 253 } }, - TestCase{ .hex = "0x00000000", .expected = &[_]u8{ 0, 0, 0, 0 } }, - TestCase{ .hex = "0xc78009fd", .expected = &[_]u8{ 199, 128, 9, 253 } }, - TestCase{ .hex = "0xC78009FD", .expected = &[_]u8{ 199, 128, 9, 253 } }, - }; - - inline for (test_cases) |tc| { - var out = [_]u8{0} ** tc.expected.len; - _ = try hexToBytes(&out, tc.hex); - try std.testing.expectEqualSlices(u8, tc.expected, &out); - } -} diff --git a/src/state_transition/test_utils/generate_block.zig b/src/state_transition/test_utils/generate_block.zig index 45e749e1..7933ff78 100644 --- a/src/state_transition/test_utils/generate_block.zig +++ b/src/state_transition/test_utils/generate_block.zig @@ -2,7 +2,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const ssz = @import("consensus_types"); const s = @import("ssz"); -const hex = @import("hex"); +const hexToRoot = @import("root.zig").hexToRoot; const Slot = ssz.primitive.Slot.Type; const preset = @import("preset").preset; const state_transition = @import("../root.zig"); @@ -67,7 +67,7 @@ pub fn generateElectraBlock(allocator: Allocator, cached_state: *const CachedBea .slot = state.slot() + 1, // value is generated after running real state transition int test .proposer_index = 41, - .parent_root = try hex.hexToRoot("0x4e647394b6f96c1cd44938483ddf14d89b35d3f67586a59cbfd410a56efbb2b1"), + .parent_root = try hexToRoot("0x4e647394b6f96c1cd44938483ddf14d89b35d3f67586a59cbfd410a56efbb2b1"), // this could be computed later .state_root = [_]u8{0} ** 32, .body = .{ diff --git a/src/state_transition/test_utils/generate_state.zig b/src/state_transition/test_utils/generate_state.zig index cb737d4f..89a69825 100644 --- a/src/state_transition/test_utils/generate_state.zig +++ b/src/state_transition/test_utils/generate_state.zig @@ -5,7 +5,8 @@ const ForkSeq = @import("config").ForkSeq; const mainnet_chain_config = @import("config").mainnet_chain_config; const minimal_chain_config = @import("config").minimal_chain_config; const ssz = @import("consensus_types"); -const hex = @import("hex"); +const hexToRoot = @import("root.zig").hexToRoot; +const hexToBytes = @import("root.zig").hexToBytes; const ElectraBeaconState = ssz.electra.BeaconState.Type; const BLSPubkey = ssz.primitive.BLSPubkey.Type; const ValidatorIndex = ssz.primitive.ValidatorIndex.Type; @@ -35,12 +36,12 @@ pub fn generateElectraState(allocator: Allocator, chain_config: ChainConfig, val errdefer allocator.destroy(electra_state); electra_state.* = ssz.electra.BeaconState.default_value; electra_state.genesis_time = 1596546008; - electra_state.genesis_validators_root = try hex.hexToRoot("0x8a8b3f1f1e2d3c4b5a697887766554433221100ffeeddccbbaa9988776655443"); + electra_state.genesis_validators_root = try hexToRoot("0x8a8b3f1f1e2d3c4b5a697887766554433221100ffeeddccbbaa9988776655443"); // set the slot to be ready for the next epoch transition electra_state.slot = chain_config.ELECTRA_FORK_EPOCH * preset.SLOTS_PER_EPOCH + 2025 * preset.SLOTS_PER_EPOCH - 1; const current_epoch = @divFloor(electra_state.slot, preset.SLOTS_PER_EPOCH); var version: [4]u8 = undefined; - _ = try hex.hexToBytes(&version, "0x00000001"); + _ = try hexToBytes(&version, "0x00000001"); electra_state.fork = .{ .previous_version = version, .current_version = version, @@ -49,9 +50,9 @@ pub fn generateElectraState(allocator: Allocator, chain_config: ChainConfig, val electra_state.latest_block_header = .{ .slot = electra_state.slot - 1, .proposer_index = 80882, - .parent_root = try hex.hexToRoot("0x5b83c3078e474b86af60043eda82a34c3c2e5ebf83146b14d9d909aea4163ef2"), - .state_root = try hex.hexToRoot("0x2761ae355e8a53c11e0e37d5e417f8984db0c53fa83f1bc65f89c6af35a196a7"), - .body_root = try hex.hexToRoot("0x249a1962eef90e122fa2447040bfac102798b1dba9c73e5593bc5aa32eb92bfd"), + .parent_root = try hexToRoot("0x5b83c3078e474b86af60043eda82a34c3c2e5ebf83146b14d9d909aea4163ef2"), + .state_root = try hexToRoot("0x2761ae355e8a53c11e0e37d5e417f8984db0c53fa83f1bc65f89c6af35a196a7"), + .body_root = try hexToRoot("0x249a1962eef90e122fa2447040bfac102798b1dba9c73e5593bc5aa32eb92bfd"), }; electra_state.block_roots = [_][32]u8{[_]u8{1} ** 32} ** preset.SLOTS_PER_HISTORICAL_ROOT; electra_state.state_roots = [_][32]u8{[_]u8{2} ** 32} ** preset.SLOTS_PER_HISTORICAL_ROOT; @@ -79,9 +80,9 @@ pub fn generateElectraState(allocator: Allocator, chain_config: ChainConfig, val } electra_state.eth1_data = .{ - .deposit_root = try hex.hexToRoot("0xcb1f89a924cfd31224823db5a41b1643f10faa7aedf231f1e28887f6ee98c047"), + .deposit_root = try hexToRoot("0xcb1f89a924cfd31224823db5a41b1643f10faa7aedf231f1e28887f6ee98c047"), .deposit_count = pubkeys.len, - .block_hash = try hex.hexToRoot("0x701fb2869ce16d0f1d14f6705725adb0dec6799da29006dfc6fff83960298f21"), + .block_hash = try hexToRoot("0x701fb2869ce16d0f1d14f6705725adb0dec6799da29006dfc6fff83960298f21"), }; // populate sync committee @@ -106,15 +107,15 @@ pub fn generateElectraState(allocator: Allocator, chain_config: ChainConfig, val } electra_state.previous_justified_checkpoint = .{ .epoch = current_epoch - 2, - .root = try hex.hexToRoot("0x3fe60bf06a57b0956cd1f8181d26649cf8bf79e48bf82f55562e04b33d4785d4"), + .root = try hexToRoot("0x3fe60bf06a57b0956cd1f8181d26649cf8bf79e48bf82f55562e04b33d4785d4"), }; electra_state.current_justified_checkpoint = .{ .epoch = current_epoch - 1, - .root = try hex.hexToRoot("0x3ba0913d2fb5e4cbcfb0d39eb15803157c1e769d63b8619285d8fdabbd8181c7"), + .root = try hexToRoot("0x3ba0913d2fb5e4cbcfb0d39eb15803157c1e769d63b8619285d8fdabbd8181c7"), }; electra_state.finalized_checkpoint = .{ .epoch = current_epoch - 3, - .root = try hex.hexToRoot("0x122b8ff579d0c8f8a8b66326bdfec3f685007d2842f01615a0768870961ccc17"), + .root = try hexToRoot("0x122b8ff579d0c8f8a8b66326bdfec3f685007d2842f01615a0768870961ccc17"), }; // the same logic to processSyncCommitteeUpdates diff --git a/src/state_transition/test_utils/root.zig b/src/state_transition/test_utils/root.zig index 61241e69..379fac4a 100644 --- a/src/state_transition/test_utils/root.zig +++ b/src/state_transition/test_utils/root.zig @@ -1,10 +1,26 @@ const std = @import("std"); +const fmt = std.fmt; const testing = std.testing; /// Utils that could be used for different kinds of tests like int, perf pub const TestCachedBeaconStateAllForks = @import("./generate_state.zig").TestCachedBeaconStateAllForks; pub const generateElectraBlock = @import("./generate_block.zig").generateElectraBlock; +/// Convert hex to bytes with 0x-prefix support +pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 { + if (input[0] == '0' and input[1] == 'x') { + return try fmt.hexToBytes(out, input[2..]); + } else { + return try fmt.hexToBytes(out, input); + } +} + +pub fn hexToRoot(input: *const [66]u8) ![32]u8 { + var out: [32]u8 = undefined; + _ = try hexToBytes(&out, input); + return out; +} + test { testing.refAllDecls(@This()); } diff --git a/zbuild.zon b/zbuild.zon index 35928914..be7eaad5 100644 --- a/zbuild.zon +++ b/zbuild.zon @@ -56,7 +56,7 @@ }, .config = .{ .root_source_file = "src/config/root.zig", - .imports = .{ .build_options, .preset, .consensus_types, .hex, .constants }, + .imports = .{ .build_options, .preset, .consensus_types, .constants }, }, .consensus_types = .{ .root_source_file = "src/consensus_types/root.zig", @@ -91,7 +91,6 @@ .blst, .preset, .constants, - .hex, }, }, }, From 1d4ab3e2270a3ffaaf87a9bbabb5dfdf0db7c247 Mon Sep 17 00:00:00 2001 From: bing Date: Thu, 30 Oct 2025 18:49:46 +0800 Subject: [PATCH 2/5] address hex comments --- src/config/root.zig | 12 +++++++----- src/state_transition/test_utils/root.zig | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/config/root.zig b/src/config/root.zig index 65db6d6a..176dcd8d 100644 --- a/src/config/root.zig +++ b/src/config/root.zig @@ -16,11 +16,13 @@ pub const hoodi_chain_config = @import("./chain/networks/hoodi.zig").hoodi_chain pub fn hexToBytesComptime(comptime n: usize, comptime input: []const u8) [n]u8 { var out: [n]u8 = undefined; - if (input[0] == '0' and input[1] == 'x') { - _ = std.fmt.hexToBytes(&out, input[2..]) catch unreachable; - } else { - _ = std.fmt.hexToBytes(&out, input) catch unreachable; - } + const input_slice = if (std.mem.startsWith(u8, input, "0x")) + input[2..] + else + input; + + _ = std.fmt.hexToBytes(&out, input_slice) catch + @compileError(std.fmt.comptimePrint("Failed to convert hex {:x} to bytes at comptime", .{input})); return out; } diff --git a/src/state_transition/test_utils/root.zig b/src/state_transition/test_utils/root.zig index 379fac4a..470be47a 100644 --- a/src/state_transition/test_utils/root.zig +++ b/src/state_transition/test_utils/root.zig @@ -8,11 +8,11 @@ pub const generateElectraBlock = @import("./generate_block.zig").generateElectra /// Convert hex to bytes with 0x-prefix support pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 { - if (input[0] == '0' and input[1] == 'x') { + if (std.mem.startsWith(u8, input, "0x")) { return try fmt.hexToBytes(out, input[2..]); - } else { - return try fmt.hexToBytes(out, input); } + + return try fmt.hexToBytes(out, input); } pub fn hexToRoot(input: *const [66]u8) ![32]u8 { From 6d5052014063b75674146c466d5a56afdbd4e618 Mon Sep 17 00:00:00 2001 From: bing Date: Thu, 30 Oct 2025 18:52:51 +0800 Subject: [PATCH 3/5] fix build --- .github/workflows/CI.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 43599ed5..7a06fb72 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -84,9 +84,6 @@ jobs: run: | zig build test:ssz - - name: Run hex tests - run: | - zig build test:hex - name: Run config tests run: | zig build test:config From 0a4c3468d894af25efb9664c88399eba5509226f Mon Sep 17 00:00:00 2001 From: bing Date: Thu, 30 Oct 2025 18:52:51 +0800 Subject: [PATCH 4/5] fix print --- .github/workflows/CI.yml | 2 ++ src/config/root.zig | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 7a06fb72..f9d16c7a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -72,6 +72,8 @@ jobs: if: matrix.os == 'ubuntu-latest' run: zig fmt --check . +<<<<<<< Conflict 1 of 1 ++++++++ Contents of side #1 - name: Run hashing tests run: | zig build test:hashing diff --git a/src/config/root.zig b/src/config/root.zig index 176dcd8d..7ef7606b 100644 --- a/src/config/root.zig +++ b/src/config/root.zig @@ -22,7 +22,7 @@ pub fn hexToBytesComptime(comptime n: usize, comptime input: []const u8) [n]u8 { input; _ = std.fmt.hexToBytes(&out, input_slice) catch - @compileError(std.fmt.comptimePrint("Failed to convert hex {:x} to bytes at comptime", .{input})); + @compileError(std.fmt.comptimePrint("Failed to convert hex {s} to bytes at comptime", .{input})); return out; } From 693fcf34f6de89a999603435059c4a2d7ece2016 Mon Sep 17 00:00:00 2001 From: bing Date: Wed, 12 Nov 2025 17:25:08 -0300 Subject: [PATCH 5/5] fix ci.yml --- .github/workflows/CI.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f9d16c7a..7a06fb72 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -72,8 +72,6 @@ jobs: if: matrix.os == 'ubuntu-latest' run: zig fmt --check . -<<<<<<< Conflict 1 of 1 -+++++++ Contents of side #1 - name: Run hashing tests run: | zig build test:hashing