From 9472dd9746fbfcb89742f00d8e6bf8e8f2a11702 Mon Sep 17 00:00:00 2001 From: Koko Bhadra Date: Tue, 9 Jun 2026 21:02:03 -0400 Subject: [PATCH] Replace removed array-repetition operator with @splat for Zig master Zig master (0.17.0-dev) removed the ** array-multiplication operator, breaking the Zig master CI job across 39 files. Replace all single-element repeats with @splat (supported since 0.14) and comptime string repeats with "prefix" ++ @as([N]u8, @splat(c)) concatenation. Verified with zig build test on both 0.15.2 and 0.17.0-dev.813. Refs #55 --- bench/bench.zig | 8 +- bench/keccak_compare.zig | 10 +-- bench/u256_bench.zig | 2 +- src/abi_decode.zig | 46 ++++++------ src/abi_encode.zig | 24 +++--- src/access_list.zig | 8 +- src/blob.zig | 20 ++--- src/block.zig | 144 ++++++++++++++++++------------------ src/contract.zig | 6 +- src/eip712.zig | 16 ++-- src/ens/namehash.zig | 12 +-- src/ens/reverse.zig | 2 +- src/erc20.zig | 16 ++-- src/erc721.zig | 8 +- src/event.zig | 70 +++++++++--------- src/flashbots.zig | 8 +- src/hd_wallet.zig | 14 ++-- src/hex.zig | 2 +- src/keccak.zig | 4 +- src/keccak_optimized.zig | 18 ++--- src/mnemonic.zig | 6 +- src/multicall.zig | 38 +++++----- src/primitives.zig | 6 +- src/provider.zig | 10 +-- src/receipt.zig | 42 +++++------ src/rlp.zig | 4 +- src/rpc_transaction.zig | 18 ++--- src/secp256k1.zig | 22 +++--- src/secp256k1_c.zig | 2 +- src/signature.zig | 6 +- src/signer.zig | 2 +- src/state_overrides.zig | 26 +++---- src/subscription.zig | 12 +-- src/transaction.zig | 80 ++++++++++---------- src/uint256.zig | 4 +- src/wallet.zig | 10 +-- src/ws_client.zig | 6 +- src/ws_transport.zig | 12 +-- tests/integration_tests.zig | 10 +-- 39 files changed, 377 insertions(+), 377 deletions(-) diff --git a/bench/bench.zig b/bench/bench.zig index 5402b5f..ed74532 100644 --- a/bench/bench.zig +++ b/bench/bench.zig @@ -114,19 +114,19 @@ fn benchKeccak32() void { } fn benchKeccak256b() void { - const data: [256]u8 = .{0xAB} ** 256; + const data: [256]u8 = @splat(0xAB); const result = eth.keccak.hash(&data); std.mem.doNotOptimizeAway(&result); } fn benchKeccak1k() void { - const data: [1024]u8 = .{0xAB} ** 1024; + const data: [1024]u8 = @splat(0xAB); const result = eth.keccak.hash(&data); std.mem.doNotOptimizeAway(&result); } fn benchKeccak4k() void { - const data: [4096]u8 = .{0xAB} ** 4096; + const data: [4096]u8 = @splat(0xAB); const result = eth.keccak.hash(&data); std.mem.doNotOptimizeAway(&result); } @@ -475,7 +475,7 @@ pub fn main() !void { const stdout = &w.interface; try stdout.print("\n{s:<34} {s:>12} {s:>14}\n", .{ "Benchmark", "ns/op", "iters" }); - try stdout.print("{s}\n", .{"-" ** 64}); + try stdout.print("{s}\n", .{"" ++ @as([64]u8, @splat('-'))}); // Keccak256 try runAndPrint("keccak256_empty", benchKeccakEmpty, stdout); diff --git a/bench/keccak_compare.zig b/bench/keccak_compare.zig index 6bf69a6..8ea85d5 100644 --- a/bench/keccak_compare.zig +++ b/bench/keccak_compare.zig @@ -2,10 +2,10 @@ const std = @import("std"); const eth = @import("eth"); // Test data -const DATA_32: [32]u8 = .{0xAB} ** 32; -const DATA_256: [256]u8 = .{0xAB} ** 256; -const DATA_1K: [1024]u8 = .{0xAB} ** 1024; -const DATA_4K: [4096]u8 = .{0xAB} ** 4096; +const DATA_32: [32]u8 = @splat(0xAB); +const DATA_256: [256]u8 = @splat(0xAB); +const DATA_1K: [1024]u8 = @splat(0xAB); +const DATA_4K: [4096]u8 = @splat(0xAB); // ============================================================================ // Benchmark harness (same as bench.zig / u256_bench.zig) @@ -115,7 +115,7 @@ pub fn main() !void { const stdout = &w.interface; try stdout.print("\n{s:<30} {s:>12} {s:>14}\n", .{ "Benchmark", "ns/op", "iters" }); - try stdout.print("{s}\n", .{"-" ** 60}); + try stdout.print("{s}\n", .{"" ++ @as([60]u8, @splat('-'))}); // eth.zig try runAndPrint("eth.zig keccak empty", benchEthKeccakEmpty, stdout); diff --git a/bench/u256_bench.zig b/bench/u256_bench.zig index 402ec4d..b87c6e3 100644 --- a/bench/u256_bench.zig +++ b/bench/u256_bench.zig @@ -236,7 +236,7 @@ pub fn main() !void { const stdout = &w.interface; try stdout.print("\n{s:<32} {s:>12} {s:>14}\n", .{ "Benchmark", "ns/op", "iters" }); - try stdout.print("{s}\n", .{"-" ** 62}); + try stdout.print("{s}\n", .{"" ++ @as([62]u8, @splat('-'))}); try runAndPrint("u256_add", benchAdd, stdout); try runAndPrint("u256_mul_small", benchMulSmall, stdout); diff --git a/src/abi_decode.zig b/src/abi_decode.zig index 81db3b8..8d0d513 100644 --- a/src/abi_decode.zig +++ b/src/abi_decode.zig @@ -240,7 +240,7 @@ test "decode single uint256" { const allocator = testing.allocator; // Encode uint256(100) = 32 zero bytes with 0x64 at position 31 - var data: [32]u8 = [_]u8{0} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0)); data[31] = 0x64; const types = [_]AbiType{.uint256}; @@ -255,7 +255,7 @@ test "decode single address" { const allocator = testing.allocator; // Address is left-padded: 12 zero bytes + 20 address bytes - var data: [32]u8 = [_]u8{0} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0)); data[12] = 0xdE; data[13] = 0xAD; data[30] = 0xBE; @@ -275,7 +275,7 @@ test "decode single address" { test "decode bool true and false" { const allocator = testing.allocator; - var true_data: [32]u8 = [_]u8{0} ** 32; + var true_data: [32]u8 = @as([32]u8, @splat(0)); true_data[31] = 1; const types = [_]AbiType{.bool}; @@ -283,7 +283,7 @@ test "decode bool true and false" { defer freeValues(true_values, allocator); try testing.expect(true_values[0].boolean); - var false_data: [32]u8 = [_]u8{0} ** 32; + var false_data: [32]u8 = @as([32]u8, @splat(0)); const false_values = try decodeValues(&false_data, &types, allocator); defer freeValues(false_values, allocator); try testing.expect(!false_values[0].boolean); @@ -293,7 +293,7 @@ test "decode int256 negative" { const allocator = testing.allocator; // -1 in two's complement = all 0xff bytes - var data: [32]u8 = [_]u8{0xff} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0xff)); const types = [_]AbiType{.int256}; const values = try decodeValues(&data, &types, allocator); @@ -305,7 +305,7 @@ test "decode int256 negative" { test "decode fixed bytes4" { const allocator = testing.allocator; - var data: [32]u8 = [_]u8{0} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0)); data[0] = 0xde; data[1] = 0xad; data[2] = 0xbe; @@ -326,7 +326,7 @@ test "decode multiple static values" { const allocator = testing.allocator; // address, uint256, bool - var data: [96]u8 = [_]u8{0} ** 96; + var data: [96]u8 = @as([96]u8, @splat(0)); // Address at word 0 data[31] = 0x01; // uint256(100) at word 1 @@ -351,7 +351,7 @@ test "decode dynamic bytes" { // Word 0: offset = 32 (0x20) // Word 1: length = 5 // Word 2: "hello" + padding - var data: [96]u8 = [_]u8{0} ** 96; + var data: [96]u8 = @as([96]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[63] = 0x05; // length = 5 data[64] = 'h'; @@ -371,7 +371,7 @@ test "decode dynamic bytes" { test "decode string" { const allocator = testing.allocator; - var data: [96]u8 = [_]u8{0} ** 96; + var data: [96]u8 = @as([96]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[63] = 0x0b; // length = 11 @memcpy(data[64..75], "hello world"); @@ -387,7 +387,7 @@ test "decode string" { test "decode empty bytes" { const allocator = testing.allocator; - var data: [64]u8 = [_]u8{0} ** 64; + var data: [64]u8 = @as([64]u8, @splat(0)); data[31] = 0x20; // offset = 32 // length = 0 (all zeros) @@ -407,7 +407,7 @@ test "decode mixed static and dynamic" { // Word 2: 7 // Word 3: string length = 2 // Word 4: "hi" padded - var data: [160]u8 = [_]u8{0} ** 160; + var data: [160]u8 = @as([160]u8, @splat(0)); data[31] = 42; // uint256(42) data[63] = 0x60; // offset = 96 data[95] = 7; // uint256(7) @@ -428,7 +428,7 @@ test "decode mixed static and dynamic" { test "decode too short data returns error" { const allocator = testing.allocator; - const data = [_]u8{0} ** 16; // Only 16 bytes, need at least 32 + const data = @as([16]u8, @splat(0)); // Only 16 bytes, need at least 32 const types = [_]AbiType{.uint256}; const result = decodeValues(&data, &types, allocator); try testing.expectError(error.DataTooShort, result); @@ -436,7 +436,7 @@ test "decode too short data returns error" { test "decode empty types returns empty slice" { const allocator = testing.allocator; - const data = [_]u8{0} ** 32; + const data = @as([32]u8, @splat(0)); const types = [_]AbiType{}; const values = try decodeValues(&data, &types, allocator); defer freeValues(values, allocator); @@ -446,7 +446,7 @@ test "decode empty types returns empty slice" { test "decode invalid bool returns error" { const allocator = testing.allocator; - var data: [32]u8 = [_]u8{0} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0)); data[31] = 2; // Invalid bool value const types = [_]AbiType{.bool}; @@ -458,7 +458,7 @@ test "encode then decode roundtrip - static types" { const allocator = testing.allocator; const encode_mod = @import("abi_encode.zig"); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xdE; addr[1] = 0xAD; addr[19] = 0xEF; @@ -522,7 +522,7 @@ test "encode then decode roundtrip - mixed static and dynamic" { const allocator = testing.allocator; const encode_mod = @import("abi_encode.zig"); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xAB; const original = [_]AbiValue{ @@ -572,7 +572,7 @@ test "decodeFunctionReturn works same as decodeValues" { const allocator = testing.allocator; // Encode a simple return: bool(true) - var data: [32]u8 = [_]u8{0} ** 32; + var data: [32]u8 = @as([32]u8, @splat(0)); data[31] = 1; const types = [_]AbiType{.bool}; @@ -585,7 +585,7 @@ test "decodeFunctionReturn works same as decodeValues" { test "decode uint8 and uint128" { const allocator = testing.allocator; - var data: [64]u8 = [_]u8{0} ** 64; + var data: [64]u8 = @as([64]u8, @splat(0)); data[31] = 0xFF; // uint8 max = 255 data[47] = 0x01; // uint128 = 1 << 120 // rest zeros @@ -690,7 +690,7 @@ test "decode large dynamic bytes 100 bytes" { // Word 1: length = 100 (0x64) // Words 2-5: 100 bytes of 0xAA + 28 bytes zero padding = 128 bytes // Total: 32 + 32 + 128 = 192 bytes - var data: [192]u8 = [_]u8{0} ** 192; + var data: [192]u8 = @as([192]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[63] = 0x64; // length = 100 for (64..164) |i| { @@ -714,7 +714,7 @@ test "decode large string 128 bytes" { // Word 1: length = 128 (0x80) // Words 2-5: 128 bytes of 'B' (0x42), exactly 4 words, no padding needed // Total: 32 + 32 + 128 = 192 bytes - var data: [192]u8 = [_]u8{0} ** 192; + var data: [192]u8 = @as([192]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[62] = 0x00; data[63] = 0x80; // length = 128 @@ -736,7 +736,7 @@ test "decode offset out of bounds" { const allocator = testing.allocator; // 64-byte buffer where word 0 has offset pointing to position 200 - var data: [64]u8 = [_]u8{0} ** 64; + var data: [64]u8 = @as([64]u8, @splat(0)); data[31] = 200; // offset = 200 (way past end of 64-byte buffer) const types = [_]AbiType{.bytes}; @@ -748,7 +748,7 @@ test "decode length out of bounds" { const allocator = testing.allocator; // 96-byte buffer: word 0 = offset 0x20, word 1 = length 9999 - var data: [96]u8 = [_]u8{0} ** 96; + var data: [96]u8 = @as([96]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[62] = 0x27; // 9999 = 0x270F data[63] = 0x0F; @@ -764,7 +764,7 @@ test "decode bytes exact 32-byte alignment" { // 64 bytes of data = exactly 2 words, no padding needed // Word 0: offset = 0x20, Word 1: length = 64, Words 2-3: 64 bytes of 0xBB // Total: 32 + 32 + 64 = 128 bytes - var data: [128]u8 = [_]u8{0} ** 128; + var data: [128]u8 = @as([128]u8, @splat(0)); data[31] = 0x20; // offset = 32 data[63] = 0x40; // length = 64 for (64..128) |i| { diff --git a/src/abi_encode.zig b/src/abi_encode.zig index 2d0855a..e8982e4 100644 --- a/src/abi_encode.zig +++ b/src/abi_encode.zig @@ -27,7 +27,7 @@ pub const AbiValue = union(enum) { tuple: []const AbiValue, pub const FixedBytes = struct { - data: [32]u8 = [_]u8{0} ** 32, + data: [32]u8 = @as([32]u8, @splat(0)), len: u8, }; @@ -179,17 +179,17 @@ fn encodeStaticValueNoAlloc(buf: *std.ArrayList(u8), val: AbiValue) void { writeUint256NoAlloc(buf, unsigned); }, .address => |v| { - var word: [32]u8 = [_]u8{0} ** 32; + var word: [32]u8 = @as([32]u8, @splat(0)); @memcpy(word[12..32], &v); buf.appendSliceAssumeCapacity(&word); }, .boolean => |v| { - var word: [32]u8 = [_]u8{0} ** 32; + var word: [32]u8 = @as([32]u8, @splat(0)); if (v) word[31] = 1; buf.appendSliceAssumeCapacity(&word); }, .fixed_bytes => |v| { - var word: [32]u8 = [_]u8{0} ** 32; + var word: [32]u8 = @as([32]u8, @splat(0)); const size: usize = @intCast(v.len); @memcpy(word[0..size], v.data[0..size]); buf.appendSliceAssumeCapacity(&word); @@ -419,7 +419,7 @@ test "encode single uint256" { test "encode single address" { const allocator = testing.allocator; - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xde; addr[1] = 0xad; addr[18] = 0xbe; @@ -569,7 +569,7 @@ test "encode dynamic array" { test "encode multiple static values" { const allocator = testing.allocator; - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[19] = 0x01; const values = [_]AbiValue{ @@ -594,7 +594,7 @@ test "encode multiple static values" { test "encode mixed static and dynamic" { const allocator = testing.allocator; - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[19] = 0x01; const values = [_]AbiValue{ @@ -635,7 +635,7 @@ test "encodeFunctionCall - transfer(address,uint256)" { const selector = [_]u8{ 0xa9, 0x05, 0x9c, 0xbb }; // transfer(0x000...0001, 100) - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[19] = 0x01; const values = [_]AbiValue{ @@ -667,7 +667,7 @@ test "encodeFunctionCall - full transfer encoding" { const sel = keccak_mod.selector("transfer(address,uint256)"); try testing.expectEqualSlices(u8, &.{ 0xa9, 0x05, 0x9c, 0xbb }, &sel); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xdE; addr[1] = 0xAD; @@ -766,7 +766,7 @@ test "encode int256 min value" { test "encode bytes exactly 32 bytes - no padding needed" { const allocator = testing.allocator; - const data = [_]u8{0xab} ** 32; + const data = @as([32]u8, @splat(0xab)); const values = [_]AbiValue{.{ .bytes = &data }}; const encoded = try encodeValues(allocator, &values); defer allocator.free(encoded); @@ -849,7 +849,7 @@ test "encodeFunctionCall - balanceOf(address)" { const sel = keccak_mod.selector("balanceOf(address)"); try testing.expectEqualSlices(u8, &.{ 0x70, 0xa0, 0x82, 0x31 }, &sel); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xd8; addr[1] = 0xdA; addr[19] = 0x45; @@ -1047,7 +1047,7 @@ test "encode ERC20 approve exact bytes" { test "encode large string 100 bytes" { const allocator = testing.allocator; - const data = [_]u8{'A'} ** 100; + const data = @as([100]u8, @splat('A')); const values = [_]AbiValue{.{ .string = &data }}; const encoded = try encodeValues(allocator, &values); defer allocator.free(encoded); diff --git a/src/access_list.zig b/src/access_list.zig index 5240d72..5aa22e3 100644 --- a/src/access_list.zig +++ b/src/access_list.zig @@ -108,7 +108,7 @@ test "empty access list encodes as empty RLP list" { test "access list with one item, no storage keys" { const allocator = std.testing.allocator; - const addr = [_]u8{0xaa} ** 20; + const addr = @as([20]u8, @splat(0xaa)); const items = [_]AccessListItem{ .{ @@ -134,8 +134,8 @@ test "access list with one item, no storage keys" { test "access list with one item and one storage key" { const allocator = std.testing.allocator; - const addr = [_]u8{0xbb} ** 20; - const key = [_]u8{0xcc} ** 32; + const addr = @as([20]u8, @splat(0xbb)); + const key = @as([32]u8, @splat(0xcc)); const keys = [_][32]u8{key}; const items = [_]AccessListItem{ @@ -162,7 +162,7 @@ test "access list with one item and one storage key" { test "access list item struct has correct fields" { const item = AccessListItem{ - .address = [_]u8{0} ** 20, + .address = @as([20]u8, @splat(0)), .storage_keys = &.{}, }; try std.testing.expectEqual(@as(usize, 20), item.address.len); diff --git a/src/blob.zig b/src/blob.zig index eaf7395..e5cce72 100644 --- a/src/blob.zig +++ b/src/blob.zig @@ -53,7 +53,7 @@ test "BLOB_SIZE is 128 KiB" { } test "computeVersionedHash sets version byte" { - const commitment = [_]u8{0xaa} ** 48; + const commitment = @as([48]u8, @splat(0xaa)); const versioned = computeVersionedHash(commitment); // First byte must be 0x01 (KZG version) @@ -65,22 +65,22 @@ test "computeVersionedHash sets version byte" { } test "computeVersionedHash deterministic" { - const commitment = [_]u8{0x42} ** 48; + const commitment = @as([48]u8, @splat(0x42)); const h1 = computeVersionedHash(commitment); const h2 = computeVersionedHash(commitment); try std.testing.expectEqualSlices(u8, &h1, &h2); } test "computeVersionedHash different commitments produce different hashes" { - const c1 = [_]u8{0x01} ** 48; - const c2 = [_]u8{0x02} ** 48; + const c1 = @as([48]u8, @splat(0x01)); + const c2 = @as([48]u8, @splat(0x02)); const h1 = computeVersionedHash(c1); const h2 = computeVersionedHash(c2); try std.testing.expect(!std.mem.eql(u8, &h1, &h2)); } test "isValidVersionedHash" { - const commitment = [_]u8{0xbb} ** 48; + const commitment = @as([48]u8, @splat(0xbb)); const valid = computeVersionedHash(commitment); try std.testing.expect(isValidVersionedHash(valid)); @@ -91,24 +91,24 @@ test "isValidVersionedHash" { } test "verifyVersionedHash" { - const commitment = [_]u8{0xcc} ** 48; + const commitment = @as([48]u8, @splat(0xcc)); const h = computeVersionedHash(commitment); try std.testing.expect(verifyVersionedHash(h, commitment)); // Wrong commitment - const wrong_commitment = [_]u8{0xdd} ** 48; + const wrong_commitment = @as([48]u8, @splat(0xdd)); try std.testing.expect(!verifyVersionedHash(h, wrong_commitment)); } test "BlobSidecar struct layout" { // Verify the struct can be instantiated (mostly a compile-time check). // Use a small stack check - don't actually allocate a full blob on the stack in release. - const commitment = [_]u8{0x11} ** 48; - const proof = [_]u8{0x22} ** 48; + const commitment = @as([48]u8, @splat(0x11)); + const proof = @as([48]u8, @splat(0x22)); _ = BlobSidecar{ - .blob = [_]u8{0} ** BLOB_SIZE, + .blob = @as([BLOB_SIZE]u8, @splat(0)), .commitment = commitment, .proof = proof, }; diff --git a/src/block.zig b/src/block.zig index 6dc64b9..9ef53ef 100644 --- a/src/block.zig +++ b/src/block.zig @@ -49,21 +49,21 @@ pub fn isProofOfStake(header: BlockHeader) bool { test "BlockHeader struct layout" { const header = BlockHeader{ .number = 17_000_000, - .hash = [_]u8{0xaa} ** 32, - .parent_hash = [_]u8{0xbb} ** 32, + .hash = @as([32]u8, @splat(0xaa)), + .parent_hash = @as([32]u8, @splat(0xbb)), .nonce = 0, - .sha3_uncles = [_]u8{0xcc} ** 32, - .miner = [_]u8{0x11} ** 20, - .state_root = [_]u8{0xdd} ** 32, - .transactions_root = [_]u8{0xee} ** 32, - .receipts_root = [_]u8{0xff} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0xcc)), + .miner = @as([20]u8, @splat(0x11)), + .state_root = @as([32]u8, @splat(0xdd)), + .transactions_root = @as([32]u8, @splat(0xee)), + .receipts_root = @as([32]u8, @splat(0xff)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_681_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 20_000_000_000, .blob_gas_used = null, .excess_blob_gas = null, @@ -78,21 +78,21 @@ test "BlockHeader struct layout" { test "isEip1559" { const pre_london = BlockHeader{ .number = 12_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 42, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 1_000_000, .gas_limit = 15_000_000, .gas_used = 10_000_000, .timestamp = 1_600_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = null, .blob_gas_used = null, .excess_blob_gas = null, @@ -100,21 +100,21 @@ test "isEip1559" { const post_london = BlockHeader{ .number = 13_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 0, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_700_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 10_000_000_000, .blob_gas_used = null, .excess_blob_gas = null, @@ -127,21 +127,21 @@ test "isEip1559" { test "isEip4844" { const dencun = BlockHeader{ .number = 19_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 0, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_710_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 10_000_000_000, .blob_gas_used = 131072, .excess_blob_gas = 0, @@ -149,21 +149,21 @@ test "isEip4844" { const pre_dencun = BlockHeader{ .number = 17_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 0, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_680_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 10_000_000_000, .blob_gas_used = null, .excess_blob_gas = null, @@ -176,21 +176,21 @@ test "isEip4844" { test "isProofOfStake" { const pos = BlockHeader{ .number = 17_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 0, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_700_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 10_000_000_000, .blob_gas_used = null, .excess_blob_gas = null, @@ -198,21 +198,21 @@ test "isProofOfStake" { const pow = BlockHeader{ .number = 12_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = 12345, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 5_000_000_000_000, .gas_limit = 15_000_000, .gas_used = 10_000_000, .timestamp = 1_600_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = null, .blob_gas_used = null, .excess_blob_gas = null, @@ -225,21 +225,21 @@ test "isProofOfStake" { test "isProofOfStake with null nonce" { const pos_null_nonce = BlockHeader{ .number = 17_000_000, - .hash = [_]u8{0} ** 32, - .parent_hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), + .parent_hash = @as([32]u8, @splat(0)), .nonce = null, - .sha3_uncles = [_]u8{0} ** 32, - .miner = [_]u8{0} ** 20, - .state_root = [_]u8{0} ** 32, - .transactions_root = [_]u8{0} ** 32, - .receipts_root = [_]u8{0} ** 32, - .logs_bloom = [_]u8{0} ** 256, + .sha3_uncles = @as([32]u8, @splat(0)), + .miner = @as([20]u8, @splat(0)), + .state_root = @as([32]u8, @splat(0)), + .transactions_root = @as([32]u8, @splat(0)), + .receipts_root = @as([32]u8, @splat(0)), + .logs_bloom = @as([256]u8, @splat(0)), .difficulty = 0, .gas_limit = 30_000_000, .gas_used = 15_000_000, .timestamp = 1_700_000_000, .extra_data = &.{}, - .mix_hash = [_]u8{0} ** 32, + .mix_hash = @as([32]u8, @splat(0)), .base_fee_per_gas = 10_000_000_000, .blob_gas_used = null, .excess_blob_gas = null, diff --git a/src/contract.zig b/src/contract.zig index 71a7dde..da54f1a 100644 --- a/src/contract.zig +++ b/src/contract.zig @@ -109,7 +109,7 @@ pub const Contract = struct { // ============================================================================ test "Contract.init sets fields correctly" { - const contract_addr = [_]u8{0xaa} ** 20; + const contract_addr = @as([20]u8, @splat(0xaa)); var transport = http_transport_mod.HttpTransport.init(std.testing.allocator, "http://localhost:8545"); defer transport.deinit(); var provider = provider_mod.Provider.init(std.testing.allocator, &transport); @@ -128,7 +128,7 @@ test "Contract.readRaw encodes function call correctly" { // Simulate what readRaw does internally: encode a balanceOf(address) call const keccak = @import("keccak.zig"); const selector = keccak.selector("balanceOf(address)"); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xd8; addr[19] = 0x45; @@ -147,7 +147,7 @@ test "Contract.writeRaw encodes transfer call correctly" { const keccak = @import("keccak.zig"); const selector = keccak.selector("transfer(address,uint256)"); - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[19] = 0x01; const values = [_]abi_encode.AbiValue{ diff --git a/src/eip712.zig b/src/eip712.zig index 1261bca..da6aff3 100644 --- a/src/eip712.zig +++ b/src/eip712.zig @@ -141,12 +141,12 @@ pub fn encodeData( return uint256_mod.toBigEndianBytes(as_u256); }, .address => |v| { - var result: [32]u8 = [_]u8{0} ** 32; + var result: [32]u8 = @as([32]u8, @splat(0)); @memcpy(result[12..32], &v); return result; }, .bool_val => |v| { - var result: [32]u8 = [_]u8{0} ** 32; + var result: [32]u8 = @as([32]u8, @splat(0)); if (v) result[31] = 1; return result; }, @@ -550,14 +550,14 @@ test "hashType - Mail type from EIP-712 spec" { test "encodeData - uint256" { const allocator = testing.allocator; const result = try encodeData(allocator, .{ .uint256 = 1 }, "uint256", &.{}); - var expected: [32]u8 = [_]u8{0} ** 32; + var expected: [32]u8 = @as([32]u8, @splat(0)); expected[31] = 1; try testing.expectEqualSlices(u8, &expected, &result); } test "encodeData - address" { const allocator = testing.allocator; - var addr: [20]u8 = [_]u8{0} ** 20; + var addr: [20]u8 = @as([20]u8, @splat(0)); addr[0] = 0xCC; addr[19] = 0xCC; const result = try encodeData(allocator, .{ .address = addr }, "address", &.{}); @@ -597,7 +597,7 @@ test "encodeData - int256 negative" { const allocator = testing.allocator; const result = try encodeData(allocator, .{ .int256 = -1 }, "int256", &.{}); // -1 in two's complement is all 0xFF bytes - var expected: [32]u8 = [_]u8{0xFF} ** 32; + var expected: [32]u8 = @as([32]u8, @splat(0xFF)); _ = &expected; try testing.expectEqualSlices(u8, &expected, &result); } @@ -819,7 +819,7 @@ test "hashDomain - with salt" { const domain = DomainSeparator{ .name = "Test", - .salt = [_]u8{0xAB} ** 32, + .salt = @as([32]u8, @splat(0xAB)), }; const result = try hashDomain(allocator, domain); @@ -852,7 +852,7 @@ test "encodeData - array of uint256" { test "encodeData - bytes32" { const allocator = testing.allocator; - var val: [32]u8 = [_]u8{0} ** 32; + var val: [32]u8 = @as([32]u8, @splat(0)); val[0] = 0xDE; val[31] = 0xAD; const result = try encodeData(allocator, .{ .bytes32 = val }, "bytes32", &.{}); @@ -1080,7 +1080,7 @@ test "hashDomain with all 5 fields" { .version = "2", .chain_id = 137, .verifying_contract = try hex.hexToBytesFixed(20, "0x1234567890123456789012345678901234567890"), - .salt = [_]u8{0xAB} ** 32, + .salt = @as([32]u8, @splat(0xAB)), }; const hash1 = try hashDomain(allocator, domain); diff --git a/src/ens/namehash.zig b/src/ens/namehash.zig index 44f1a7f..5fb8318 100644 --- a/src/ens/namehash.zig +++ b/src/ens/namehash.zig @@ -8,9 +8,9 @@ const keccak = @import("../keccak.zig"); /// namehash("eth") = keccak256(namehash("") ++ keccak256("eth")) /// namehash("foo.eth") = keccak256(namehash("eth") ++ keccak256("foo")) pub fn namehash(name: []const u8) [32]u8 { - if (name.len == 0) return [_]u8{0} ** 32; + if (name.len == 0) return @as([32]u8, @splat(0)); - var node: [32]u8 = [_]u8{0} ** 32; + var node: [32]u8 = @as([32]u8, @splat(0)); // We need to process labels right-to-left. First, find all label boundaries. // Walk backwards through the name to find dot positions. @@ -52,7 +52,7 @@ const hex = @import("../hex.zig"); test "namehash empty string" { const result = namehash(""); - const expected = [_]u8{0} ** 32; + const expected = @as([32]u8, @splat(0)); try std.testing.expectEqualSlices(u8, &expected, &result); } @@ -87,7 +87,7 @@ test "namehash deep subdomain" { // a.b.c.eth should process right-to-left: eth -> c -> b -> a const result = namehash("a.b.c.eth"); // Verify it manually step by step - var node: [32]u8 = [_]u8{0} ** 32; + var node: [32]u8 = @as([32]u8, @splat(0)); // eth const eth_label = keccak.hash("eth"); node = keccak.hashConcat(&.{ &node, ð_label }); @@ -119,7 +119,7 @@ test "labelhash is just keccak256 of the label" { test "namehash single label (no dots)" { // A single label like "eth" should produce: keccak256(0x00..00 ++ keccak256("eth")) const result = namehash("eth"); - var node: [32]u8 = [_]u8{0} ** 32; + var node: [32]u8 = @as([32]u8, @splat(0)); const eth_hash = keccak.hash("eth"); node = keccak.hashConcat(&.{ &node, ð_hash }); try std.testing.expectEqualSlices(u8, &node, &result); @@ -143,7 +143,7 @@ test "namehash vitalik.eth official" { test "namehash resolver.eth" { // Manually compute: node starts as zeros, then hash "eth", then hash "resolver" - var node: [32]u8 = [_]u8{0} ** 32; + var node: [32]u8 = @as([32]u8, @splat(0)); const eth_label = keccak.hash("eth"); node = keccak.hashConcat(&.{ &node, ð_label }); const resolver_label = keccak.hash("resolver"); diff --git a/src/ens/reverse.zig b/src/ens/reverse.zig index 7c75c4f..7a1b270 100644 --- a/src/ens/reverse.zig +++ b/src/ens/reverse.zig @@ -168,7 +168,7 @@ test "reverseNameOf produces correct format" { test "reverseNameOf length is always 53" { const allocator = std.testing.allocator; - const addr: Address = [_]u8{0xff} ** 20; + const addr: Address = @as([20]u8, @splat(0xff)); const result = try reverseNameOf(allocator, addr); defer allocator.free(result); diff --git a/src/erc20.zig b/src/erc20.zig index 98722f1..b02822a 100644 --- a/src/erc20.zig +++ b/src/erc20.zig @@ -219,7 +219,7 @@ test "ERC20 Approval topic matches known value" { } test "ERC20.init sets address correctly" { - const token_addr = [_]u8{0xaa} ** 20; + const token_addr = @as([20]u8, @splat(0xaa)); var transport = http_transport_mod.HttpTransport.init(std.testing.allocator, "http://localhost:8545"); defer transport.deinit(); var prov = provider_mod.Provider.init(std.testing.allocator, &transport); @@ -231,7 +231,7 @@ test "ERC20.init sets address correctly" { test "ERC20 transfer encodes correctly" { // Verify the encoding that transfer would produce const allocator = std.testing.allocator; - var to_addr: [20]u8 = [_]u8{0} ** 20; + var to_addr: [20]u8 = @as([20]u8, @splat(0)); to_addr[19] = 0x01; const args = [_]AbiValue{ .{ .address = to_addr }, .{ .uint256 = 1000 } }; @@ -245,7 +245,7 @@ test "ERC20 transfer encodes correctly" { test "ERC20 balanceOf encodes correctly" { const allocator = std.testing.allocator; - var holder: [20]u8 = [_]u8{0} ** 20; + var holder: [20]u8 = @as([20]u8, @splat(0)); holder[0] = 0xd8; holder[19] = 0x45; @@ -259,7 +259,7 @@ test "ERC20 balanceOf encodes correctly" { test "ERC20 approve encodes correctly" { const allocator = std.testing.allocator; - var spender: [20]u8 = [_]u8{0} ** 20; + var spender: [20]u8 = @as([20]u8, @splat(0)); spender[19] = 0x02; const args = [_]AbiValue{ .{ .address = spender }, .{ .uint256 = 500 } }; @@ -272,9 +272,9 @@ test "ERC20 approve encodes correctly" { test "ERC20 transferFrom encodes correctly" { const allocator = std.testing.allocator; - var from: [20]u8 = [_]u8{0} ** 20; + var from: [20]u8 = @as([20]u8, @splat(0)); from[19] = 0x01; - var to: [20]u8 = [_]u8{0} ** 20; + var to: [20]u8 = @as([20]u8, @splat(0)); to[19] = 0x02; const args = [_]AbiValue{ .{ .address = from }, .{ .address = to }, .{ .uint256 = 100 } }; @@ -288,9 +288,9 @@ test "ERC20 transferFrom encodes correctly" { test "ERC20 allowance encodes correctly" { const allocator = std.testing.allocator; - var owner: [20]u8 = [_]u8{0} ** 20; + var owner: [20]u8 = @as([20]u8, @splat(0)); owner[19] = 0x01; - var spender: [20]u8 = [_]u8{0} ** 20; + var spender: [20]u8 = @as([20]u8, @splat(0)); spender[19] = 0x02; const args = [_]AbiValue{ .{ .address = owner }, .{ .address = spender } }; diff --git a/src/erc721.zig b/src/erc721.zig index f82c893..3c9d0d7 100644 --- a/src/erc721.zig +++ b/src/erc721.zig @@ -260,7 +260,7 @@ test "ERC721 ApprovalForAll topic matches known value" { } test "ERC721.init sets address correctly" { - const nft_addr = [_]u8{0xbb} ** 20; + const nft_addr = @as([20]u8, @splat(0xbb)); var transport = http_transport_mod.HttpTransport.init(std.testing.allocator, "http://localhost:8545"); defer transport.deinit(); var prov = provider_mod.Provider.init(std.testing.allocator, &transport); @@ -271,9 +271,9 @@ test "ERC721.init sets address correctly" { test "ERC721 transferFrom encodes correctly" { const allocator = std.testing.allocator; - var from: [20]u8 = [_]u8{0} ** 20; + var from: [20]u8 = @as([20]u8, @splat(0)); from[19] = 0x01; - var to: [20]u8 = [_]u8{0} ** 20; + var to: [20]u8 = @as([20]u8, @splat(0)); to[19] = 0x02; const args = [_]AbiValue{ .{ .address = from }, .{ .address = to }, .{ .uint256 = 42 } }; @@ -297,7 +297,7 @@ test "ERC721 ownerOf encodes correctly" { test "ERC721 setApprovalForAll encodes correctly" { const allocator = std.testing.allocator; - var operator: [20]u8 = [_]u8{0} ** 20; + var operator: [20]u8 = @as([20]u8, @splat(0)); operator[19] = 0x03; const args = [_]AbiValue{ .{ .address = operator }, .{ .boolean = true } }; diff --git a/src/event.zig b/src/event.zig index 60c93aa..cf80def 100644 --- a/src/event.zig +++ b/src/event.zig @@ -77,16 +77,16 @@ pub fn decodeLog(log: *const receipt_mod.Log) DecodedLog { // ============================================================================ test "logMatchesTopic matches correctly" { - const transfer_topic = [_]u8{0xdd} ** 32; - const approval_topic = [_]u8{0xaa} ** 32; + const transfer_topic = @as([32]u8, @splat(0xdd)); + const approval_topic = @as([32]u8, @splat(0xaa)); const topics = [_][32]u8{transfer_topic}; const log = receipt_mod.Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &topics, .data = &.{}, .block_number = 100, - .transaction_hash = [_]u8{0xcc} ** 32, + .transaction_hash = @as([32]u8, @splat(0xcc)), .transaction_index = 0, .log_index = 0, .block_hash = null, @@ -99,7 +99,7 @@ test "logMatchesTopic matches correctly" { test "logMatchesTopic returns false for empty topics" { const log = receipt_mod.Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &.{}, .data = &.{}, .block_number = null, @@ -110,17 +110,17 @@ test "logMatchesTopic returns false for empty topics" { .removed = false, }; - try std.testing.expect(!logMatchesTopic(&log, [_]u8{0xaa} ** 32)); + try std.testing.expect(!logMatchesTopic(&log, @as([32]u8, @splat(0xaa)))); } test "getIndexedTopics extracts topics[1..]" { - const topic0 = [_]u8{0xdd} ** 32; - const topic1 = [_]u8{0x11} ** 32; - const topic2 = [_]u8{0x22} ** 32; + const topic0 = @as([32]u8, @splat(0xdd)); + const topic1 = @as([32]u8, @splat(0x11)); + const topic2 = @as([32]u8, @splat(0x22)); const topics = [_][32]u8{ topic0, topic1, topic2 }; const log = receipt_mod.Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &topics, .data = &.{}, .block_number = null, @@ -138,9 +138,9 @@ test "getIndexedTopics extracts topics[1..]" { } test "getIndexedTopics returns empty for single topic" { - const topics = [_][32]u8{[_]u8{0xdd} ** 32}; + const topics = [_][32]u8{@as([32]u8, @splat(0xdd))}; const log = receipt_mod.Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &topics, .data = &.{}, .block_number = null, @@ -157,7 +157,7 @@ test "getIndexedTopics returns empty for single topic" { test "getIndexedTopics returns empty for no topics" { const log = receipt_mod.Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &.{}, .data = &.{}, .block_number = null, @@ -175,41 +175,41 @@ test "getIndexedTopics returns empty for no topics" { test "filterLogsByTopic filters matching logs" { const allocator = std.testing.allocator; - const transfer_topic = [_]u8{0xdd} ** 32; - const approval_topic = [_]u8{0xaa} ** 32; + const transfer_topic = @as([32]u8, @splat(0xdd)); + const approval_topic = @as([32]u8, @splat(0xaa)); const transfer_topics = [_][32]u8{transfer_topic}; const approval_topics = [_][32]u8{approval_topic}; const logs = [_]receipt_mod.Log{ .{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &transfer_topics, .data = &.{ 0x01, 0x02 }, .block_number = 100, - .transaction_hash = [_]u8{0xcc} ** 32, + .transaction_hash = @as([32]u8, @splat(0xcc)), .transaction_index = 0, .log_index = 0, .block_hash = null, .removed = false, }, .{ - .address = [_]u8{0x22} ** 20, + .address = @as([20]u8, @splat(0x22)), .topics = &approval_topics, .data = &.{ 0x03, 0x04 }, .block_number = 100, - .transaction_hash = [_]u8{0xcc} ** 32, + .transaction_hash = @as([32]u8, @splat(0xcc)), .transaction_index = 0, .log_index = 1, .block_hash = null, .removed = false, }, .{ - .address = [_]u8{0x33} ** 20, + .address = @as([20]u8, @splat(0x33)), .topics = &transfer_topics, .data = &.{ 0x05, 0x06 }, .block_number = 101, - .transaction_hash = [_]u8{0xdd} ** 32, + .transaction_hash = @as([32]u8, @splat(0xdd)), .transaction_index = 0, .log_index = 0, .block_hash = null, @@ -221,20 +221,20 @@ test "filterLogsByTopic filters matching logs" { defer allocator.free(filtered); try std.testing.expectEqual(@as(usize, 2), filtered.len); - try std.testing.expectEqualSlices(u8, &([_]u8{0x11} ** 20), &filtered[0].address); - try std.testing.expectEqualSlices(u8, &([_]u8{0x33} ** 20), &filtered[1].address); + try std.testing.expectEqualSlices(u8, &(@as([20]u8, @splat(0x11))), &filtered[0].address); + try std.testing.expectEqualSlices(u8, &(@as([20]u8, @splat(0x33))), &filtered[1].address); } test "filterLogsByTopic returns empty for no matches" { const allocator = std.testing.allocator; - const transfer_topic = [_]u8{0xdd} ** 32; - const other_topic = [_]u8{0xff} ** 32; + const transfer_topic = @as([32]u8, @splat(0xdd)); + const other_topic = @as([32]u8, @splat(0xff)); const topics = [_][32]u8{transfer_topic}; const logs = [_]receipt_mod.Log{ .{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &topics, .data = &.{}, .block_number = null, @@ -253,27 +253,27 @@ test "filterLogsByTopic returns empty for no matches" { } test "decodeLog extracts all fields" { - const topic0 = [_]u8{0xdd} ** 32; - const from_topic = [_]u8{0x11} ** 32; - const to_topic = [_]u8{0x22} ** 32; + const topic0 = @as([32]u8, @splat(0xdd)); + const from_topic = @as([32]u8, @splat(0x11)); + const to_topic = @as([32]u8, @splat(0x22)); const topics = [_][32]u8{ topic0, from_topic, to_topic }; - const data = [_]u8{0x00} ** 32; + const data = @as([32]u8, @splat(0x00)); const log = receipt_mod.Log{ - .address = [_]u8{0xaa} ** 20, + .address = @as([20]u8, @splat(0xaa)), .topics = &topics, .data = &data, .block_number = 12345, - .transaction_hash = [_]u8{0xbb} ** 32, + .transaction_hash = @as([32]u8, @splat(0xbb)), .transaction_index = 3, .log_index = 7, - .block_hash = [_]u8{0xcc} ** 32, + .block_hash = @as([32]u8, @splat(0xcc)), .removed = false, }; const decoded = decodeLog(&log); - try std.testing.expectEqualSlices(u8, &([_]u8{0xaa} ** 20), &decoded.address); + try std.testing.expectEqualSlices(u8, &(@as([20]u8, @splat(0xaa))), &decoded.address); try std.testing.expectEqual(@as(usize, 2), decoded.indexed_values.len); try std.testing.expectEqualSlices(u8, &from_topic, &decoded.indexed_values[0]); try std.testing.expectEqualSlices(u8, &to_topic, &decoded.indexed_values[1]); @@ -284,7 +284,7 @@ test "decodeLog extracts all fields" { test "DecodedLog struct default values" { const decoded = DecodedLog{ - .address = [_]u8{0} ** 20, + .address = @as([20]u8, @splat(0)), .indexed_values = &.{}, .data = &.{}, .block_number = null, diff --git a/src/flashbots.zig b/src/flashbots.zig index f6f4a4c..f43c184 100644 --- a/src/flashbots.zig +++ b/src/flashbots.zig @@ -802,7 +802,7 @@ test "buildSendBundleParams - with optional fields" { const allocator = std.testing.allocator; const tx = &[_]u8{0xff}; const txs = [_][]const u8{tx}; - const hash = [_]u8{0xaa} ** 32; + const hash = @as([32]u8, @splat(0xaa)); const hashes = [_][32]u8{hash}; const params = try buildSendBundleParams(allocator, .{ @@ -873,7 +873,7 @@ test "buildMevSendBundleParams - basic" { test "buildMevSendBundleParams - with hash body and privacy" { const allocator = std.testing.allocator; - const hash = [_]u8{0xbb} ** 32; + const hash = @as([32]u8, @splat(0xbb)); const body = [_]MevBundleBody{ .{ .hash = hash }, }; @@ -926,7 +926,7 @@ test "parseBundleHashResult - success" { ; const result = try parseBundleHashResult(std.testing.allocator, raw); - const expected = [_]u8{0xaa} ** 32; + const expected = @as([32]u8, @splat(0xaa)); try std.testing.expectEqualSlices(u8, &expected, &result.bundle_hash); } @@ -951,7 +951,7 @@ test "parseCallBundleResult - success with decimal strings" { ; const result = try parseCallBundleResult(std.testing.allocator, raw); - const expected_hash = [_]u8{0xbb} ** 32; + const expected_hash = @as([32]u8, @splat(0xbb)); try std.testing.expectEqualSlices(u8, &expected_hash, &result.bundle_hash); try std.testing.expectEqual(@as(u256, 476190476193), result.bundle_gas_price); try std.testing.expectEqual(@as(u256, 20000000000126000), result.coinbase_diff); diff --git a/src/hd_wallet.zig b/src/hd_wallet.zig index 70bacd3..3b718f8 100644 --- a/src/hd_wallet.zig +++ b/src/hd_wallet.zig @@ -149,7 +149,7 @@ pub fn deriveEthAccount(seed: [64]u8, account_index: u32) HdWalletError!Extended // Tests test "masterKeyFromSeed produces deterministic results" { - const seed = [_]u8{0x01} ** 64; + const seed = @as([64]u8, @splat(0x01)); const key1 = try masterKeyFromSeed(seed); const key2 = try masterKeyFromSeed(seed); try std.testing.expectEqualSlices(u8, &key1.key, &key2.key); @@ -157,7 +157,7 @@ test "masterKeyFromSeed produces deterministic results" { } test "deriveChild produces different keys for different indices" { - const seed = [_]u8{0x42} ** 64; + const seed = @as([64]u8, @splat(0x42)); const master = try masterKeyFromSeed(seed); const child0 = try deriveChild(master, HARDENED); const child1 = try deriveChild(master, 1 | HARDENED); @@ -165,21 +165,21 @@ test "deriveChild produces different keys for different indices" { } test "derivePath m/44'/60'/0'/0/0" { - const seed = [_]u8{0xab} ** 64; + const seed = @as([64]u8, @splat(0xab)); const key_path = try derivePath(seed, "m/44'/60'/0'/0/0"); const key_manual = try deriveEthAccount(seed, 0); try std.testing.expectEqualSlices(u8, &key_path.key, &key_manual.key); } test "derivePath just m returns master key" { - const seed = [_]u8{0xcd} ** 64; + const seed = @as([64]u8, @splat(0xcd)); const master = try masterKeyFromSeed(seed); const key_m = try derivePath(seed, "m"); try std.testing.expectEqualSlices(u8, &master.key, &key_m.key); } test "toAddress produces 20-byte address" { - const seed = [_]u8{0xef} ** 64; + const seed = @as([64]u8, @splat(0xef)); const key = try deriveEthAccount(seed, 0); const addr = try key.toAddress(); // Just verify it's not all zeros @@ -194,7 +194,7 @@ test "toAddress produces 20-byte address" { } test "different accounts produce different addresses" { - const seed = [_]u8{0x11} ** 64; + const seed = @as([64]u8, @splat(0x11)); const key0 = try deriveEthAccount(seed, 0); const key1 = try deriveEthAccount(seed, 1); const addr0 = try key0.toAddress(); @@ -234,7 +234,7 @@ test "known BIP-39 mnemonic to address" { test "BIP-32 master key from known seed" { const hex_mod = @import("hex.zig"); // Known 64-byte seed (first 32 bytes from hex, rest zero) - var seed: [64]u8 = [_]u8{0} ** 64; + var seed: [64]u8 = @as([64]u8, @splat(0)); const first_half = try hex_mod.hexToBytesFixed(32, "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); @memcpy(seed[0..32], &first_half); diff --git a/src/hex.zig b/src/hex.zig index 46b17c7..bc0d2ff 100644 --- a/src/hex.zig +++ b/src/hex.zig @@ -10,7 +10,7 @@ pub const HexError = error{ /// Comptime-generated lookup table for hex decoding. /// Maps ASCII byte -> nibble value (0-15), or 0xFF for invalid characters. const hex_lut: [256]u8 = blk: { - var table: [256]u8 = .{0xFF} ** 256; + var table: [256]u8 = @splat(0xFF); for ('0'..('9' + 1)) |c| table[c] = c - '0'; for ('a'..('f' + 1)) |c| table[c] = c - 'a' + 10; for ('A'..('F' + 1)) |c| table[c] = c - 'A' + 10; diff --git a/src/keccak.zig b/src/keccak.zig index 8f83a00..172a29e 100644 --- a/src/keccak.zig +++ b/src/keccak.zig @@ -88,7 +88,7 @@ test "keccak256 testing" { } test "keccak256 256 zero bytes" { - const zero_bytes = [_]u8{0} ** 256; + const zero_bytes = @as([256]u8, @splat(0)); const result1 = hash(&zero_bytes); const result2 = hash(&zero_bytes); // Verify 32-byte output @@ -98,7 +98,7 @@ test "keccak256 256 zero bytes" { } test "keccak256 4KB input" { - const big_input = [_]u8{0x42} ** 4096; + const big_input = @as([4096]u8, @splat(0x42)); const result1 = hash(&big_input); const result2 = hash(&big_input); // Verify determinism diff --git a/src/keccak_optimized.zig b/src/keccak_optimized.zig index 6b23b14..31ad4a2 100644 --- a/src/keccak_optimized.zig +++ b/src/keccak_optimized.zig @@ -30,7 +30,7 @@ const COMPLEMENT_LANES = [25]bool{ /// Optimized Keccak-256 hash. Lane complementing + interleaved rounds. pub fn keccak256(data: []const u8) [32]u8 { - var state: [25]u64 = [_]u64{0} ** 25; + var state: [25]u64 = @as([25]u64, @splat(0)); // Apply lane complement to initial zero state (complement of 0 = ~0) inline for (0..25) |i| { @@ -45,7 +45,7 @@ pub fn keccak256(data: []const u8) [32]u8 { } // Final block with padding (Keccak: 0x01 || 0x00...0x00 || 0x80) - var last: [RATE]u8 = [_]u8{0} ** RATE; + var last: [RATE]u8 = @as([RATE]u8, @splat(0)); const remaining = data.len - offset; @memcpy(last[0..remaining], data[offset..][0..remaining]); last[remaining] = 0x01; @@ -223,49 +223,49 @@ test "optimized keccak256 testing" { } test "optimized keccak256 exactly 1 block (136 bytes)" { - const data = [_]u8{0x42} ** 136; + const data = @as([136]u8, @splat(0x42)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 rate-1 boundary (135 bytes)" { - const data = [_]u8{0xAB} ** 135; + const data = @as([135]u8, @splat(0xAB)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 rate+1 boundary (137 bytes)" { - const data = [_]u8{0xCD} ** 137; + const data = @as([137]u8, @splat(0xCD)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 multi-block 256 bytes" { - const data = [_]u8{0xAB} ** 256; + const data = @as([256]u8, @splat(0xAB)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 multi-block 1KB" { - const data = [_]u8{0xAB} ** 1024; + const data = @as([1024]u8, @splat(0xAB)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 multi-block 4KB" { - const data = [_]u8{0x42} ** 4096; + const data = @as([4096]u8, @splat(0x42)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); } test "optimized keccak256 large input 64KB" { - const data = [_]u8{0xFF} ** 65536; + const data = @as([65536]u8, @splat(0xFF)); const result = keccak256(&data); const expected = stdlibHash(&data); try std.testing.expectEqualSlices(u8, &expected, &result); diff --git a/src/mnemonic.zig b/src/mnemonic.zig index 5a251ac..e359906 100644 --- a/src/mnemonic.zig +++ b/src/mnemonic.zig @@ -118,7 +118,7 @@ pub fn validate(words: []const []const u8) MnemonicError!void { const checksum_bits = entropy_size.checksumBits(); // Convert words to 11-bit indices - var bits: [33]u8 = [_]u8{0} ** 33; // max 264 bits = 33 bytes + var bits: [33]u8 = @as([33]u8, @splat(0)); // max 264 bits = 33 bytes for (words, 0..) |word, i| { const index = wordToIndex(word) orelse return error.InvalidWord; @@ -294,7 +294,7 @@ test "validate rejects bad checksum" { test "entropyToMnemonic known vector" { // All-zero entropy should produce "abandon" x 11 + "about" - const entropy = [_]u8{0} ** 16; + const entropy = @as([16]u8, @splat(0)); const words = entropyToMnemonic(.@"128", &entropy); for (0..11) |i| { try std.testing.expectEqualStrings("abandon", words[i]); @@ -327,7 +327,7 @@ test "BIP-39 TREZOR passphrase exact seed vector" { } test "BIP-39 all-ones entropy produces zoo...wrong" { - const entropy = [_]u8{0xFF} ** 16; + const entropy = @as([16]u8, @splat(0xFF)); const words = entropyToMnemonic(.@"128", &entropy); for (0..11) |i| { try std.testing.expectEqualStrings("zoo", words[i]); diff --git a/src/multicall.zig b/src/multicall.zig index 6b2a946..02a3ca2 100644 --- a/src/multicall.zig +++ b/src/multicall.zig @@ -141,7 +141,7 @@ pub const Multicall = struct { // Tuple bodies for (self.calls.items) |c| { // address (left-padded to 32 bytes) - var addr_word: [32]u8 = [_]u8{0} ** 32; + var addr_word: [32]u8 = @as([32]u8, @splat(0)); @memcpy(addr_word[12..32], &c.target); try buf.appendSlice(self.allocator, &addr_word); @@ -271,7 +271,7 @@ test "Multicall.init and deinit" { var transport = http_transport_mod.HttpTransport.init(allocator, "http://localhost:8545"); defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - const multicall_addr = [_]u8{0xca} ** 20; + const multicall_addr = @as([20]u8, @splat(0xca)); var mc = Multicall.init(allocator, &provider, multicall_addr); defer mc.deinit(); @@ -286,11 +286,11 @@ test "Multicall.addCall adds calls" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); - const target1 = [_]u8{0x11} ** 20; - const target2 = [_]u8{0x22} ** 20; + const target1 = @as([20]u8, @splat(0x11)); + const target2 = @as([20]u8, @splat(0x22)); const calldata1 = [_]u8{ 0xa9, 0x05, 0x9c, 0xbb }; const calldata2 = [_]u8{ 0x70, 0xa0, 0x82, 0x31 }; @@ -310,11 +310,11 @@ test "Multicall.reset clears calls" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); - try mc.addCall([_]u8{0x11} ** 20, &.{0x01}, false); - try mc.addCall([_]u8{0x22} ** 20, &.{0x02}, true); + try mc.addCall(@as([20]u8, @splat(0x11)), &.{0x01}, false); + try mc.addCall(@as([20]u8, @splat(0x22)), &.{0x02}, true); try std.testing.expectEqual(@as(usize, 2), mc.calls.items.len); mc.reset(); @@ -327,10 +327,10 @@ test "Multicall.encodeAggregate3 produces valid ABI encoding" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); - const target = [_]u8{0x11} ** 20; + const target = @as([20]u8, @splat(0x11)); const calldata = [_]u8{ 0x70, 0xa0, 0x82, 0x31 }; // balanceOf selector try mc.addCall(target, &calldata, false); @@ -358,11 +358,11 @@ test "Multicall.encodeAggregate3 with multiple calls" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); - const target1 = [_]u8{0x11} ** 20; - const target2 = [_]u8{0x22} ** 20; + const target1 = @as([20]u8, @splat(0x11)); + const target2 = @as([20]u8, @splat(0x22)); const calldata1 = [_]u8{ 0x70, 0xa0, 0x82, 0x31 }; const calldata2 = [_]u8{ 0xa9, 0x05, 0x9c, 0xbb, 0x00 }; // 5 bytes @@ -388,10 +388,10 @@ test "Multicall.encodeAggregate3 with empty calldata" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); - try mc.addCall([_]u8{0x11} ** 20, &.{}, true); + try mc.addCall(@as([20]u8, @splat(0x11)), &.{}, true); const encoded = try mc.encodeAggregate3(); defer allocator.free(encoded); @@ -412,7 +412,7 @@ test "decodeAggregate3Results decodes single result" { // word 4: offset to bytes = 0x40 // word 5: bytes length = 4 // word 6: bytes data (0x00000064 + padding) - var data: [7 * 32]u8 = [_]u8{0} ** (7 * 32); + var data: [7 * 32]u8 = @splat(0); // word 0: offset = 0x20 data[31] = 0x20; @@ -445,7 +445,7 @@ test "decodeAggregate3Results decodes failed result" { const allocator = std.testing.allocator; // Build output for: [(false, 0x)] - var data: [6 * 32]u8 = [_]u8{0} ** (6 * 32); + var data: [6 * 32]u8 = @splat(0); // word 0: offset = 0x20 data[31] = 0x20; @@ -490,11 +490,11 @@ test "Multicall.encodeAggregate3 address encoding" { defer transport.deinit(); var provider = provider_mod.Provider.init(allocator, &transport); - var mc = Multicall.init(allocator, &provider, [_]u8{0xca} ** 20); + var mc = Multicall.init(allocator, &provider, @as([20]u8, @splat(0xca))); defer mc.deinit(); // Use a known address to verify left-padding - var target: [20]u8 = [_]u8{0} ** 20; + var target: [20]u8 = @as([20]u8, @splat(0)); target[0] = 0xde; target[1] = 0xad; target[18] = 0xbe; diff --git a/src/primitives.zig b/src/primitives.zig index 536961f..f77fbbc 100644 --- a/src/primitives.zig +++ b/src/primitives.zig @@ -8,7 +8,7 @@ const keccak = @import("keccak.zig"); pub const Address = [20]u8; /// Zero address (0x0000...0000). -pub const ZERO_ADDRESS: Address = [_]u8{0} ** 20; +pub const ZERO_ADDRESS: Address = @as([20]u8, @splat(0)); /// Parse an address from a hex string (with optional "0x" prefix). pub fn addressFromHex(hex_str: []const u8) hex_mod.HexError!Address { @@ -75,7 +75,7 @@ pub const Hash = [32]u8; pub const Bytes32 = [32]u8; /// Zero hash. -pub const ZERO_HASH: Hash = [_]u8{0} ** 32; +pub const ZERO_HASH: Hash = @as([32]u8, @splat(0)); /// Parse a Hash/Bytes32 from a hex string. pub fn hashFromHex(hex_str: []const u8) hex_mod.HexError!Hash { @@ -172,7 +172,7 @@ test "addressFromHex wrong length error" { } test "addressToHex all-0xFF roundtrip" { - const addr: Address = [_]u8{0xFF} ** 20; + const addr: Address = @as([20]u8, @splat(0xFF)); const hex = addressToHex(&addr); try std.testing.expectEqualStrings("0xffffffffffffffffffffffffffffffffffffffff", &hex); diff --git a/src/provider.zig b/src/provider.zig index 3d77c88..e93bd0f 100644 --- a/src/provider.zig +++ b/src/provider.zig @@ -987,7 +987,7 @@ pub fn parseBlockHeader(allocator: std.mem.Allocator, raw: []const u8) !?block_m const gas_limit = try parseHexU64(jsonGetString(obj, "gasLimit") orelse return error.InvalidResponse); const gas_used = try parseHexU64(jsonGetString(obj, "gasUsed") orelse return error.InvalidResponse); const timestamp = try parseHexU64(jsonGetString(obj, "timestamp") orelse return error.InvalidResponse); - const mix_hash = try parseHash(jsonGetString(obj, "mixHash") orelse "0x" ++ "00" ** 32); + const mix_hash = try parseHash(jsonGetString(obj, "mixHash") orelse "0x" ++ @as([64]u8, @splat('0'))); // Parse extraData const extra_data_str = jsonGetString(obj, "extraData") orelse "0x"; @@ -1551,7 +1551,7 @@ test "parseBlockHeader - basic block" { const allocator = std.testing.allocator; // Build a bloom of 256 zero bytes = "0x" + 512 '0' chars - const bloom_hex = "0x" ++ "00" ** 256; + const bloom_hex = "0x" ++ @as([512]u8, @splat('0')); const raw = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{" ++ "\"number\":\"0x1036640\"," ++ @@ -1662,8 +1662,8 @@ test "BatchCaller.addCall accumulates" { var batch = BatchCaller.init(allocator, &prov); defer batch.deinit(); - const idx0 = try batch.addCall([_]u8{0x11} ** 20, &.{ 0x01, 0x02 }); - const idx1 = try batch.addCall([_]u8{0x22} ** 20, &.{ 0x03, 0x04 }); + const idx0 = try batch.addCall(@as([20]u8, @splat(0x11)), &.{ 0x01, 0x02 }); + const idx1 = try batch.addCall(@as([20]u8, @splat(0x22)), &.{ 0x03, 0x04 }); try std.testing.expectEqual(@as(usize, 0), idx0); try std.testing.expectEqual(@as(usize, 1), idx1); @@ -1678,7 +1678,7 @@ test "BatchCaller.reset clears" { var batch = BatchCaller.init(allocator, &prov); defer batch.deinit(); - _ = try batch.addCall([_]u8{0x11} ** 20, &.{0x01}); + _ = try batch.addCall(@as([20]u8, @splat(0x11)), &.{0x01}); try std.testing.expectEqual(@as(usize, 1), batch.targets.items.len); batch.reset(); try std.testing.expectEqual(@as(usize, 0), batch.targets.items.len); diff --git a/src/receipt.zig b/src/receipt.zig index 2a66225..fe3a8cc 100644 --- a/src/receipt.zig +++ b/src/receipt.zig @@ -51,12 +51,12 @@ pub fn logCount(receipt: TransactionReceipt) usize { test "TransactionReceipt struct layout" { const receipt = TransactionReceipt{ - .transaction_hash = [_]u8{0xaa} ** 32, - .block_hash = [_]u8{0xbb} ** 32, + .transaction_hash = @as([32]u8, @splat(0xaa)), + .block_hash = @as([32]u8, @splat(0xbb)), .block_number = 12_345_678, .transaction_index = 42, - .from = [_]u8{0x11} ** 20, - .to = [_]u8{0x22} ** 20, + .from = @as([20]u8, @splat(0x11)), + .to = @as([20]u8, @splat(0x22)), .gas_used = 21000, .cumulative_gas_used = 500_000, .effective_gas_price = 20_000_000_000, @@ -76,11 +76,11 @@ test "TransactionReceipt struct layout" { test "isSuccess" { var receipt = TransactionReceipt{ - .transaction_hash = [_]u8{0} ** 32, - .block_hash = [_]u8{0} ** 32, + .transaction_hash = @as([32]u8, @splat(0)), + .block_hash = @as([32]u8, @splat(0)), .block_number = 0, .transaction_index = 0, - .from = [_]u8{0} ** 20, + .from = @as([20]u8, @splat(0)), .to = null, .gas_used = 0, .cumulative_gas_used = 0, @@ -99,11 +99,11 @@ test "isSuccess" { test "isContractCreation" { var receipt = TransactionReceipt{ - .transaction_hash = [_]u8{0} ** 32, - .block_hash = [_]u8{0} ** 32, + .transaction_hash = @as([32]u8, @splat(0)), + .block_hash = @as([32]u8, @splat(0)), .block_number = 0, .transaction_index = 0, - .from = [_]u8{0} ** 20, + .from = @as([20]u8, @splat(0)), .to = null, .gas_used = 0, .cumulative_gas_used = 0, @@ -116,25 +116,25 @@ test "isContractCreation" { try std.testing.expect(!isContractCreation(receipt)); - receipt.contract_address = [_]u8{0xff} ** 20; + receipt.contract_address = @as([20]u8, @splat(0xff)); try std.testing.expect(isContractCreation(receipt)); } test "Log struct layout" { const topics = [_][32]u8{ - [_]u8{0xaa} ** 32, - [_]u8{0xbb} ** 32, + @as([32]u8, @splat(0xaa)), + @as([32]u8, @splat(0xbb)), }; const log = Log{ - .address = [_]u8{0x11} ** 20, + .address = @as([20]u8, @splat(0x11)), .topics = &topics, .data = &.{ 0x01, 0x02, 0x03 }, .block_number = 100, - .transaction_hash = [_]u8{0xcc} ** 32, + .transaction_hash = @as([32]u8, @splat(0xcc)), .transaction_index = 5, .log_index = 12, - .block_hash = [_]u8{0xdd} ** 32, + .block_hash = @as([32]u8, @splat(0xdd)), .removed = false, }; @@ -147,7 +147,7 @@ test "Log struct layout" { test "logCount" { const logs = [_]Log{ .{ - .address = [_]u8{0} ** 20, + .address = @as([20]u8, @splat(0)), .topics = &.{}, .data = &.{}, .block_number = null, @@ -158,7 +158,7 @@ test "logCount" { .removed = false, }, .{ - .address = [_]u8{0} ** 20, + .address = @as([20]u8, @splat(0)), .topics = &.{}, .data = &.{}, .block_number = null, @@ -171,11 +171,11 @@ test "logCount" { }; const receipt = TransactionReceipt{ - .transaction_hash = [_]u8{0} ** 32, - .block_hash = [_]u8{0} ** 32, + .transaction_hash = @as([32]u8, @splat(0)), + .block_hash = @as([32]u8, @splat(0)), .block_number = 0, .transaction_index = 0, - .from = [_]u8{0} ** 20, + .from = @as([20]u8, @splat(0)), .to = null, .gas_used = 0, .cumulative_gas_used = 0, diff --git a/src/rlp.zig b/src/rlp.zig index c2d0846..1fce295 100644 --- a/src/rlp.zig +++ b/src/rlp.zig @@ -654,7 +654,7 @@ test "encode-decode roundtrip u256 max" { test "encode long string 56 bytes" { const allocator = std.testing.allocator; - const data: [56]u8 = .{0xAA} ** 56; + const data: [56]u8 = @splat(0xAA); const result = try encode(allocator, @as([]const u8, &data)); defer allocator.free(result); // Long string: prefix = 0xb8 (0x80 + 55 + 1), length byte = 0x38 (56) @@ -664,7 +664,7 @@ test "encode long string 56 bytes" { test "encode long string 256 bytes" { const allocator = std.testing.allocator; - const data: [256]u8 = .{0xBB} ** 256; + const data: [256]u8 = @splat(0xBB); const result = try encode(allocator, @as([]const u8, &data)); defer allocator.free(result); // Long string: prefix = 0xb9 (0x80 + 55 + 2), length = 256 = 0x01 0x00 diff --git a/src/rpc_transaction.zig b/src/rpc_transaction.zig index aaa8d79..b48498e 100644 --- a/src/rpc_transaction.zig +++ b/src/rpc_transaction.zig @@ -77,13 +77,13 @@ pub fn freeRpcTransaction(allocator: std.mem.Allocator, tx: RpcTransaction) void test "RpcTransaction struct layout" { const tx = RpcTransaction{ - .hash = [_]u8{0xaa} ** 32, + .hash = @as([32]u8, @splat(0xaa)), .nonce = 5, .block_hash = null, .block_number = null, .transaction_index = null, - .from = [_]u8{0x11} ** 20, - .to = [_]u8{0x22} ** 20, + .from = @as([20]u8, @splat(0x11)), + .to = @as([20]u8, @splat(0x22)), .value = 1_000_000_000_000_000_000, .gas = 21_000, .gas_price = 20_000_000_000, @@ -92,8 +92,8 @@ test "RpcTransaction struct layout" { .max_fee_per_blob_gas = null, .input = &.{}, .v = 27, - .r = [_]u8{0x33} ** 32, - .s = [_]u8{0x44} ** 32, + .r = @as([32]u8, @splat(0x33)), + .s = @as([32]u8, @splat(0x44)), .type_ = 0, .chain_id = 1, }; @@ -110,12 +110,12 @@ test "freeRpcTransaction frees the input slice" { const input = try allocator.alloc(u8, 4); @memcpy(input, "abcd"); const tx = RpcTransaction{ - .hash = [_]u8{0} ** 32, + .hash = @as([32]u8, @splat(0)), .nonce = 0, .block_hash = null, .block_number = null, .transaction_index = null, - .from = [_]u8{0} ** 20, + .from = @as([20]u8, @splat(0)), .to = null, .value = 0, .gas = 0, @@ -125,8 +125,8 @@ test "freeRpcTransaction frees the input slice" { .max_fee_per_blob_gas = null, .input = input, .v = 0, - .r = [_]u8{0} ** 32, - .s = [_]u8{0} ** 32, + .r = @as([32]u8, @splat(0)), + .s = @as([32]u8, @splat(0)), .type_ = 2, .chain_id = null, }; diff --git a/src/secp256k1.zig b/src/secp256k1.zig index 8c358fb..20f7455 100644 --- a/src/secp256k1.zig +++ b/src/secp256k1.zig @@ -278,11 +278,11 @@ fn generateRfc6979Nonce(private_key: [32]u8, message_hash: [32]u8) Scalar { // Step a: h1 = message_hash (already provided, 32 bytes) // Step b: V = 0x01 0x01 ... 0x01 (32 bytes of 0x01) - var v: [32]u8 = [_]u8{0x01} ** 32; + var v: [32]u8 = @as([32]u8, @splat(0x01)); defer secureZero(&v); // Step c: K = 0x00 0x00 ... 0x00 (32 bytes of 0x00) - var k: [32]u8 = [_]u8{0x00} ** 32; + var k: [32]u8 = @as([32]u8, @splat(0x00)); defer secureZero(&k); // Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) @@ -345,7 +345,7 @@ fn reduceFieldElement(bytes: [32]u8) Scalar { return s; } else |_| {} // If the value >= order, reduce it using reduce64 with zero-padding - var padded: [64]u8 = [_]u8{0} ** 64; + var padded: [64]u8 = @as([64]u8, @splat(0)); @memcpy(padded[32..64], &bytes); return Scalar.fromBytes(Secp256k1.scalar.reduce64(padded, .big), .big) catch unreachable; } @@ -457,8 +457,8 @@ test "sign different messages produce different signatures" { test "recover fails with invalid recovery ID" { const sig = Signature{ - .r = [_]u8{0} ** 31 ++ [_]u8{1}, - .s = [_]u8{0} ** 31 ++ [_]u8{1}, + .r = @as([31]u8, @splat(0)) ++ [_]u8{1}, + .s = @as([31]u8, @splat(0)) ++ [_]u8{1}, .v = 2, }; const hash = keccak.hash("test"); @@ -467,8 +467,8 @@ test "recover fails with invalid recovery ID" { test "recover fails with zero r" { const sig = Signature{ - .r = [_]u8{0} ** 32, - .s = [_]u8{0} ** 31 ++ [_]u8{1}, + .r = @as([32]u8, @splat(0)), + .s = @as([31]u8, @splat(0)) ++ [_]u8{1}, .v = 0, }; const hash = keccak.hash("test"); @@ -477,8 +477,8 @@ test "recover fails with zero r" { test "recover fails with zero s" { const sig = Signature{ - .r = [_]u8{0} ** 31 ++ [_]u8{1}, - .s = [_]u8{0} ** 32, + .r = @as([31]u8, @splat(0)) ++ [_]u8{1}, + .s = @as([32]u8, @splat(0)), .v = 0, }; const hash = keccak.hash("test"); @@ -486,7 +486,7 @@ test "recover fails with zero s" { } test "sign rejects zero private key" { - const zero_key = [_]u8{0} ** 32; + const zero_key = @as([32]u8, @splat(0)); const hash = keccak.hash("test"); try std.testing.expectError(error.InvalidPrivateKey, sign(zero_key, hash)); } @@ -578,7 +578,7 @@ test "sign and recover with second test key" { test "sign with small private key (key=1)" { // Private key = 1 (31 zero bytes + 0x01) - var private_key: [32]u8 = [_]u8{0} ** 32; + var private_key: [32]u8 = @as([32]u8, @splat(0)); private_key[31] = 0x01; const message_hash = keccak.hash("test"); diff --git a/src/secp256k1_c.zig b/src/secp256k1_c.zig index bd85a97..ee2ba1a 100644 --- a/src/secp256k1_c.zig +++ b/src/secp256k1_c.zig @@ -136,7 +136,7 @@ pub fn recover(sig: Signature, message_hash: [32]u8) RecoverError![65]u8 { if (sig.v > 1) return error.InvalidRecoveryId; // Validate r and s are non-zero - const zero = [_]u8{0} ** 32; + const zero = @as([32]u8, @splat(0)); if (std.mem.eql(u8, &sig.r, &zero) or std.mem.eql(u8, &sig.s, &zero)) { return error.InvalidSignature; } diff --git a/src/signature.zig b/src/signature.zig index d2c7142..76a518d 100644 --- a/src/signature.zig +++ b/src/signature.zig @@ -58,8 +58,8 @@ pub const Signature = struct { test "Signature toBytes and fromBytes roundtrip" { const sig = Signature{ - .r = [_]u8{0} ** 31 ++ [_]u8{0x01}, - .s = [_]u8{0} ** 31 ++ [_]u8{0x02}, + .r = @as([31]u8, @splat(0)) ++ [_]u8{0x01}, + .s = @as([31]u8, @splat(0)) ++ [_]u8{0x02}, .v = 1, }; @@ -128,7 +128,7 @@ test "Signature eql" { } test "Signature fromBytes with zero signature" { - const bytes = [_]u8{0} ** 65; + const bytes = @as([65]u8, @splat(0)); const sig = Signature.fromBytes(bytes); try std.testing.expectEqual(@as(u256, 0), sig.toRSV().r); diff --git a/src/signer.zig b/src/signer.zig index 5b80f45..e655a9c 100644 --- a/src/signer.zig +++ b/src/signer.zig @@ -244,7 +244,7 @@ test "Signer with Hardhat account #4" { } test "hashPersonalMessage with 100-byte message" { - const message: [100]u8 = [_]u8{'A'} ** 100; + const message: [100]u8 = @as([100]u8, @splat('A')); const hash = Signer.hashPersonalMessage(&message); // The prefix for a 100-byte message includes "100" (3 chars) diff --git a/src/state_overrides.zig b/src/state_overrides.zig index 0b72240..f2a9c9b 100644 --- a/src/state_overrides.zig +++ b/src/state_overrides.zig @@ -245,7 +245,7 @@ test "StateOverrides - balance only" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xaa} ** 20; + const addr = @as([20]u8, @splat(0xaa)); try ov.setBalance(addr, 0x1234); const json = try ov.serializeJson(allocator); @@ -261,7 +261,7 @@ test "StateOverrides - nonce, code, balance combined for one address" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xbb} ** 20; + const addr = @as([20]u8, @splat(0xbb)); try ov.setBalance(addr, 100); try ov.setNonce(addr, 7); try ov.setCode(addr, &.{ 0x60, 0x80 }); @@ -279,12 +279,12 @@ test "StateOverrides - stateDiff merges multiple slots" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xcc} ** 20; - var slot1: [32]u8 = .{0} ** 32; + const addr = @as([20]u8, @splat(0xcc)); + var slot1: [32]u8 = @splat(0); slot1[31] = 0x01; - var slot2: [32]u8 = .{0} ** 32; + var slot2: [32]u8 = @splat(0); slot2[31] = 0x02; - var val: [32]u8 = .{0} ** 32; + var val: [32]u8 = @splat(0); val[31] = 0xff; try ov.setStorageAt(addr, slot1, val); @@ -305,10 +305,10 @@ test "StateOverrides - full state replacement uses state not stateDiff" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xdd} ** 20; - var slot: [32]u8 = .{0} ** 32; + const addr = @as([20]u8, @splat(0xdd)); + var slot: [32]u8 = @splat(0); slot[31] = 0x05; - var val: [32]u8 = .{0} ** 32; + var val: [32]u8 = @splat(0); val[31] = 0x42; try ov.setFullStorage(addr, slot, val); @@ -324,7 +324,7 @@ test "StateOverrides - setCode replaces previous bytecode without leak" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xee} ** 20; + const addr = @as([20]u8, @splat(0xee)); try ov.setCode(addr, &.{ 0x01, 0x02 }); try ov.setCode(addr, &.{ 0xab, 0xcd, 0xef }); // The testing allocator catches leaks; this asserts that the first @@ -340,7 +340,7 @@ test "StateOverrides - setBalance is idempotent on the same address" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr = [_]u8{0xff} ** 20; + const addr = @as([20]u8, @splat(0xff)); try ov.setBalance(addr, 1); try ov.setBalance(addr, 2); try ov.setBalance(addr, 3); @@ -355,8 +355,8 @@ test "StateOverrides - multiple addresses round-trip" { var ov = StateOverrides.init(allocator); defer ov.deinit(); - const addr_a = [_]u8{0x11} ** 20; - const addr_b = [_]u8{0x22} ** 20; + const addr_a = @as([20]u8, @splat(0x11)); + const addr_b = @as([20]u8, @splat(0x22)); try ov.setBalance(addr_a, 5); try ov.setBalance(addr_b, 7); diff --git a/src/subscription.zig b/src/subscription.zig index e2aff48..87aaaf4 100644 --- a/src/subscription.zig +++ b/src/subscription.zig @@ -530,7 +530,7 @@ test "buildSubscribeParams - newPendingTransactions full" { test "buildSubscribeParams - logs with address only" { const allocator = std.testing.allocator; - const addr = [_]u8{0xde} ** 20; + const addr = @as([20]u8, @splat(0xde)); const params: SubscriptionParams = .{ .logs = .{ .address = addr, @@ -548,7 +548,7 @@ test "buildSubscribeParams - logs with address only" { test "buildSubscribeParams - logs with topics" { const allocator = std.testing.allocator; - const topic1 = [_]u8{0xAA} ** 32; + const topic1 = @as([32]u8, @splat(0xAA)); const topics = [_]?[32]u8{topic1}; const params: SubscriptionParams = .{ .logs = .{ @@ -580,9 +580,9 @@ test "buildSubscribeParams - logs with null topic" { test "buildSubscribeParams - logs with address and topics" { const allocator = std.testing.allocator; - const addr = [_]u8{0x11} ** 20; - const topic1 = [_]u8{0x22} ** 32; - const topic2 = [_]u8{0x33} ** 32; + const addr = @as([20]u8, @splat(0x11)); + const topic1 = @as([32]u8, @splat(0x22)); + const topic2 = @as([32]u8, @splat(0x33)); const topics = [_]?[32]u8{ topic1, null, topic2 }; const params: SubscriptionParams = .{ .logs = .{ @@ -661,7 +661,7 @@ test "formatAddress" { } test "formatHash" { - const hash = [_]u8{0xAB} ** 32; + const hash = @as([32]u8, @splat(0xAB)); const result = formatHash(hash); try std.testing.expect(result[0] == '0'); try std.testing.expect(result[1] == 'x'); diff --git a/src/transaction.zig b/src/transaction.zig index 47df11f..38f4834 100644 --- a/src/transaction.zig +++ b/src/transaction.zig @@ -476,7 +476,7 @@ test "legacy tx serialization for signing (EIP-155, chain_id=1)" { .nonce = 9, .gas_price = 20_000_000_000, // 20 gwei .gas_limit = 21000, - .to = [_]u8{0x35} ** 20, + .to = @as([20]u8, @splat(0x35)), .value = 1_000_000_000_000_000_000, // 1 ETH in wei .data = &.{}, .chain_id = 1, @@ -505,7 +505,7 @@ test "legacy tx serialization without chain_id (pre-EIP-155)" { .nonce = 0, .gas_price = 1_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 0, .data = &.{}, .chain_id = null, @@ -515,7 +515,7 @@ test "legacy tx serialization without chain_id (pre-EIP-155)" { .nonce = 0, .gas_price = 1_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 0, .data = &.{}, .chain_id = 1, @@ -561,7 +561,7 @@ test "eip2930 tx serialization for signing" { .nonce = 0, .gas_price = 1_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xbb} ** 20, + .to = @as([20]u8, @splat(0xbb)), .value = 0, .data = &.{}, .access_list = &.{}, @@ -586,7 +586,7 @@ test "eip1559 tx serialization for signing" { .max_priority_fee_per_gas = 1_500_000_000, // 1.5 gwei .max_fee_per_gas = 30_000_000_000, // 30 gwei .gas_limit = 21000, - .to = [_]u8{0xcc} ** 20, + .to = @as([20]u8, @splat(0xcc)), .value = 1_000_000_000_000_000_000, .data = &.{}, .access_list = &.{}, @@ -603,7 +603,7 @@ test "eip1559 tx serialization for signing" { test "eip4844 tx serialization for signing" { const allocator = std.testing.allocator; - const hash1 = [_]u8{0x01} ++ [_]u8{0xaa} ** 31; + const hash1 = [_]u8{0x01} ++ @as([31]u8, @splat(0xaa)); const hashes = [_][32]u8{hash1}; const tx = Transaction{ .eip4844 = .{ @@ -612,7 +612,7 @@ test "eip4844 tx serialization for signing" { .max_priority_fee_per_gas = 1_000_000_000, .max_fee_per_gas = 50_000_000_000, .gas_limit = 100_000, - .to = [_]u8{0xdd} ** 20, + .to = @as([20]u8, @splat(0xdd)), .value = 0, .data = &.{}, .access_list = &.{}, @@ -634,14 +634,14 @@ test "signed legacy tx serialization" { .nonce = 9, .gas_price = 20_000_000_000, .gas_limit = 21000, - .to = [_]u8{0x35} ** 20, + .to = @as([20]u8, @splat(0x35)), .value = 1_000_000_000_000_000_000, .data = &.{}, .chain_id = 1, } }; - const r = [_]u8{0x01} ** 32; - const s = [_]u8{0x02} ** 32; + const r = @as([32]u8, @splat(0x01)); + const s = @as([32]u8, @splat(0x02)); const v: u8 = 37; // chain_id=1 => v = 1*2 + 35 + 0 = 37 const signed = try serializeSigned(allocator, tx, r, s, v); @@ -661,14 +661,14 @@ test "signed eip1559 tx serialization" { .max_priority_fee_per_gas = 1_500_000_000, .max_fee_per_gas = 30_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xcc} ** 20, + .to = @as([20]u8, @splat(0xcc)), .value = 0, .data = &.{}, .access_list = &.{}, } }; - const r = [_]u8{0xab} ** 32; - const s = [_]u8{0xcd} ** 32; + const r = @as([32]u8, @splat(0xab)); + const s = @as([32]u8, @splat(0xcd)); const v: u8 = 1; const signed = try serializeSigned(allocator, tx, r, s, v); @@ -753,8 +753,8 @@ test "legacy tx known encoding (EIP-155)" { test "eip2930 with access list" { const allocator = std.testing.allocator; - const addr = [_]u8{0x11} ** 20; - const key = [_]u8{0x22} ** 32; + const addr = @as([20]u8, @splat(0x11)); + const key = @as([32]u8, @splat(0x22)); const keys = [_][32]u8{key}; const items = [_]AccessListItem{.{ @@ -788,7 +788,7 @@ test "encodeU256Bytes strips leading zeros" { defer list.deinit(allocator); // Value with many leading zeros - var val = [_]u8{0} ** 32; + var val = @as([32]u8, @splat(0)); val[31] = 0x42; try encodeU256Bytes(allocator, &list, &val); @@ -802,7 +802,7 @@ test "encodeU256Bytes all zeros" { var list: std.ArrayList(u8) = .empty; defer list.deinit(allocator); - const val = [_]u8{0} ** 32; + const val = @as([32]u8, @splat(0)); try encodeU256Bytes(allocator, &list, &val); // Should encode as RLP 0 = 0x80 @@ -816,7 +816,7 @@ test "hashForSigning produces different hashes for different txs" { .nonce = 0, .gas_price = 1_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 0, .data = &.{}, .chain_id = 1, @@ -826,7 +826,7 @@ test "hashForSigning produces different hashes for different txs" { .nonce = 1, .gas_price = 1_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 0, .data = &.{}, .chain_id = 1, @@ -907,13 +907,13 @@ test "eip1559 with specific parameters" { test "transaction with 256-byte data" { const allocator = std.testing.allocator; - const data = [_]u8{0x42} ** 256; + const data = @as([256]u8, @splat(0x42)); const tx = Transaction{ .legacy = .{ .nonce = 1, .gas_price = 30_000_000_000, .gas_limit = 500_000, - .to = [_]u8{0xAA} ** 20, + .to = @as([20]u8, @splat(0xAA)), .value = 0, .data = &data, .chain_id = 1, @@ -929,17 +929,17 @@ test "transaction with 256-byte data" { test "access list with multiple entries" { const allocator = std.testing.allocator; - const key_aa = [_]u8{0xAA} ** 32; - const key_bb = [_]u8{0xBB} ** 32; - const key_cc = [_]u8{0xCC} ** 32; + const key_aa = @as([32]u8, @splat(0xAA)); + const key_bb = @as([32]u8, @splat(0xBB)); + const key_cc = @as([32]u8, @splat(0xCC)); const keys_1 = [_][32]u8{ key_aa, key_bb }; const keys_2 = [_][32]u8{key_cc}; const items = [_]AccessListItem{ - .{ .address = [_]u8{0x11} ** 20, .storage_keys = &keys_1 }, - .{ .address = [_]u8{0x22} ** 20, .storage_keys = &keys_2 }, - .{ .address = [_]u8{0x33} ** 20, .storage_keys = &.{} }, + .{ .address = @as([20]u8, @splat(0x11)), .storage_keys = &keys_1 }, + .{ .address = @as([20]u8, @splat(0x22)), .storage_keys = &keys_2 }, + .{ .address = @as([20]u8, @splat(0x33)), .storage_keys = &.{} }, }; const tx = Transaction{ .eip2930 = .{ @@ -947,7 +947,7 @@ test "access list with multiple entries" { .nonce = 0, .gas_price = 1_000_000_000, .gas_limit = 100_000, - .to = [_]u8{0xFF} ** 20, + .to = @as([20]u8, @splat(0xFF)), .value = 0, .data = &.{}, .access_list = &items, @@ -972,7 +972,7 @@ test "eip1559 with large fees" { .max_priority_fee_per_gas = 100_000_000_000, // 100 gwei .max_fee_per_gas = 500_000_000_000, // 500 gwei .gas_limit = 21000, - .to = [_]u8{0xBB} ** 20, + .to = @as([20]u8, @splat(0xBB)), .value = 1_000_000_000_000_000_000, // 1 ETH .data = &.{}, .access_list = &.{}, @@ -994,7 +994,7 @@ test "eip1559 with large fees" { .max_priority_fee_per_gas = 0, .max_fee_per_gas = 0, .gas_limit = 21000, - .to = [_]u8{0xBB} ** 20, + .to = @as([20]u8, @splat(0xBB)), .value = 0, .data = &.{}, .access_list = &.{}, @@ -1009,9 +1009,9 @@ test "eip1559 with large fees" { test "eip4844 with three blob hashes" { const allocator = std.testing.allocator; - const hash1 = [_]u8{0x01} ++ [_]u8{0xAA} ** 31; - const hash2 = [_]u8{0x01} ++ [_]u8{0xBB} ** 31; - const hash3 = [_]u8{0x01} ++ [_]u8{0xCC} ** 31; + const hash1 = [_]u8{0x01} ++ @as([31]u8, @splat(0xAA)); + const hash2 = [_]u8{0x01} ++ @as([31]u8, @splat(0xBB)); + const hash3 = [_]u8{0x01} ++ @as([31]u8, @splat(0xCC)); const three_hashes = [_][32]u8{ hash1, hash2, hash3 }; const one_hash = [_][32]u8{hash1}; @@ -1023,7 +1023,7 @@ test "eip4844 with three blob hashes" { .max_priority_fee_per_gas = 1_000_000_000, // 1 gwei .max_fee_per_gas = 50_000_000_000, // 50 gwei .gas_limit = 100_000, - .to = [_]u8{0xDD} ** 20, + .to = @as([20]u8, @splat(0xDD)), .value = 0, .data = &.{}, .access_list = &.{}, @@ -1038,7 +1038,7 @@ test "eip4844 with three blob hashes" { .max_priority_fee_per_gas = 1_000_000_000, .max_fee_per_gas = 50_000_000_000, .gas_limit = 100_000, - .to = [_]u8{0xDD} ** 20, + .to = @as([20]u8, @splat(0xDD)), .value = 0, .data = &.{}, .access_list = &.{}, @@ -1067,14 +1067,14 @@ test "signed eip1559 tx structure" { .max_priority_fee_per_gas = 1_500_000_000, .max_fee_per_gas = 30_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xcc} ** 20, + .to = @as([20]u8, @splat(0xcc)), .value = 0, .data = &.{}, .access_list = &.{}, } }; - const r = [_]u8{0x11} ** 32; - const s = [_]u8{0x22} ** 32; + const r = @as([32]u8, @splat(0x11)); + const s = @as([32]u8, @splat(0x22)); const v: u8 = 0; const signed = try serializeSigned(allocator, tx, r, s, v); @@ -1098,7 +1098,7 @@ test "hashForSigning different chain IDs produce different hashes" { .nonce = 0, .gas_price = 20_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 1_000_000_000_000_000_000, .data = &.{}, .chain_id = 1, @@ -1108,7 +1108,7 @@ test "hashForSigning different chain IDs produce different hashes" { .nonce = 0, .gas_price = 20_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 1_000_000_000_000_000_000, .data = &.{}, .chain_id = 5, diff --git a/src/uint256.zig b/src/uint256.zig index 9d57b99..58b4dda 100644 --- a/src/uint256.zig +++ b/src/uint256.zig @@ -706,7 +706,7 @@ test "fromHex max u256" { test "fromHex overflow" { // 65 hex chars = 260 bits > 256 bits - const too_big = "0x1" ++ "0" ** 64; + const too_big = "0x1" ++ @as([64]u8, @splat('0')); try std.testing.expectError(error.Overflow, fromHex(too_big)); } @@ -867,7 +867,7 @@ test "fromHex toHex roundtrip comprehensive" { } test "fromBigEndianBytes zero" { - const zero_bytes = [_]u8{0} ** 32; + const zero_bytes = @as([32]u8, @splat(0)); try std.testing.expectEqual(@as(u256, 0), fromBigEndianBytes(zero_bytes)); } diff --git a/src/wallet.zig b/src/wallet.zig index 0c4c7d1..0e50122 100644 --- a/src/wallet.zig +++ b/src/wallet.zig @@ -97,7 +97,7 @@ pub const Wallet = struct { break :blk try self.provider.estimateGas(to_addr, tx.data, addr); } else { // Contract deployment: estimate with zero address as placeholder - break :blk try self.provider.estimateGas([_]u8{0} ** 20, tx.data, addr); + break :blk try self.provider.estimateGas(@as([20]u8, @splat(0)), tx.data, addr); } }; @@ -197,7 +197,7 @@ test "Wallet.signTransaction produces valid signed bytes" { .max_priority_fee_per_gas = 1_500_000_000, .max_fee_per_gas = 30_000_000_000, .gas_limit = 21000, - .to = [_]u8{0xcc} ** 20, + .to = @as([20]u8, @splat(0xcc)), .value = 1_000_000_000_000_000_000, .data = &.{}, .access_list = &.{}, @@ -228,7 +228,7 @@ test "Wallet.signTransaction is deterministic" { .max_priority_fee_per_gas = 2_000_000_000, .max_fee_per_gas = 50_000_000_000, .gas_limit = 100_000, - .to = [_]u8{0xaa} ** 20, + .to = @as([20]u8, @splat(0xaa)), .value = 0, .data = &.{ 0xa9, 0x05, 0x9c, 0xbb }, .access_list = &.{}, @@ -245,7 +245,7 @@ test "Wallet.signTransaction is deterministic" { test "SendTransactionOpts defaults" { const opts = SendTransactionOpts{ - .to = [_]u8{0xbb} ** 20, + .to = @as([20]u8, @splat(0xbb)), }; try std.testing.expectEqual(@as(u256, 0), opts.value); @@ -267,7 +267,7 @@ test "SendTransactionOpts supports null to for deployment" { test "SendTransactionOpts with all fields" { const opts = SendTransactionOpts{ - .to = [_]u8{0xcc} ** 20, + .to = @as([20]u8, @splat(0xcc)), .value = 1_000_000_000_000_000_000, .data = &.{ 0x01, 0x02, 0x03 }, .gas_limit = 21000, diff --git a/src/ws_client.zig b/src/ws_client.zig index e1700f0..170845c 100644 --- a/src/ws_client.zig +++ b/src/ws_client.zig @@ -668,9 +668,9 @@ test "cloneParams + freeOwnedParams - new_heads" { test "cloneParams + freeOwnedParams - logs with topics deep copied" { const alloc = std.testing.allocator; - var local = [_]?[32]u8{ [_]u8{0xAA} ** 32, null }; + var local = [_]?[32]u8{ @as([32]u8, @splat(0xAA)), null }; const params = SubscriptionParams{ .logs = .{ - .address = [_]u8{0xCC} ** 20, + .address = @as([20]u8, @splat(0xCC)), .topics = local[0..], } }; const cloned = try cloneParams(alloc, params); @@ -678,7 +678,7 @@ test "cloneParams + freeOwnedParams - logs with topics deep copied" { // Mutating the original must not change the clone. local[0] = null; try std.testing.expect(cloned.logs.topics.?[0] != null); - try std.testing.expectEqualSlices(u8, &([_]u8{0xAA} ** 32), &cloned.logs.topics.?[0].?); + try std.testing.expectEqualSlices(u8, &(@as([32]u8, @splat(0xAA))), &cloned.logs.topics.?[0].?); } test "Opts defaults" { diff --git a/src/ws_transport.zig b/src/ws_transport.zig index a6bb5bb..326e5e7 100644 --- a/src/ws_transport.zig +++ b/src/ws_transport.zig @@ -893,7 +893,7 @@ test "encodeFrame - empty payload" { test "encodeFrame - medium payload (126 bytes)" { const allocator = std.testing.allocator; - const payload = [_]u8{'A'} ** 200; + const payload = @as([200]u8, @splat('A')); const mask_key = [4]u8{ 0x01, 0x02, 0x03, 0x04 }; const frame = try encodeFrame(allocator, .text, &payload, mask_key); @@ -1126,8 +1126,8 @@ test "generateWebSocketKey - produces 24 base64 chars" { } test "generateWebSocketKey - different inputs produce different keys" { - const key1 = generateWebSocketKey([_]u8{0} ** 16); - const key2 = generateWebSocketKey([_]u8{1} ** 16); + const key1 = generateWebSocketKey(@as([16]u8, @splat(0))); + const key2 = generateWebSocketKey(@as([16]u8, @splat(1))); try std.testing.expect(!std.mem.eql(u8, &key1, &key2)); } @@ -1246,7 +1246,7 @@ test "encodeFrame then decodeFrameHeader roundtrip" { test "encodeFrame then decodeFrameHeader roundtrip - large payload" { const allocator = std.testing.allocator; - const payload = [_]u8{'X'} ** 300; + const payload = @as([300]u8, @splat('X')); const mask_key = [4]u8{ 0xAB, 0xCD, 0xEF, 0x01 }; const frame = try encodeFrame(allocator, .binary, &payload, mask_key); @@ -1270,7 +1270,7 @@ test "encodeFrame then decodeFrameHeader roundtrip - large payload" { test "encodeFrame - exactly 125 bytes (max short length)" { const allocator = std.testing.allocator; - const payload = [_]u8{'Z'} ** 125; + const payload = @as([125]u8, @splat('Z')); const mask_key = [4]u8{ 1, 2, 3, 4 }; const frame = try encodeFrame(allocator, .text, &payload, mask_key); @@ -1283,7 +1283,7 @@ test "encodeFrame - exactly 125 bytes (max short length)" { test "encodeFrame - exactly 126 bytes (triggers extended 16-bit length)" { const allocator = std.testing.allocator; - const payload = [_]u8{'Z'} ** 126; + const payload = @as([126]u8, @splat('Z')); const mask_key = [4]u8{ 1, 2, 3, 4 }; const frame = try encodeFrame(allocator, .text, &payload, mask_key); diff --git a/tests/integration_tests.zig b/tests/integration_tests.zig index e290dbc..3364965 100644 --- a/tests/integration_tests.zig +++ b/tests/integration_tests.zig @@ -164,7 +164,7 @@ test "getBlock for block 0 returns genesis" { try std.testing.expectEqual(@as(u64, 0), header.number); // Genesis block parent hash is all zeros. - try std.testing.expectEqualSlices(u8, &([_]u8{0} ** 32), &header.parent_hash); + try std.testing.expectEqualSlices(u8, &(@as([32]u8, @splat(0))), &header.parent_hash); } test "getBlock for non-existent block returns null" { @@ -303,7 +303,7 @@ test "getTransactionReceipt for unknown hash returns null" { var provider = eth.provider.Provider.init(allocator, &transport); // A made-up transaction hash that does not exist. - const fake_hash = [_]u8{0xab} ** 32; + const fake_hash = @as([32]u8, @splat(0xab)); const receipt = try provider.getTransactionReceipt(fake_hash); try std.testing.expect(receipt == null); } @@ -359,7 +359,7 @@ test "callWithOverrides applies code + balance override" { // Returned 32 bytes encode the overridden balance. try std.testing.expectEqual(@as(usize, 32), result.len); - var expected = [_]u8{0} ** 32; + var expected = @as([32]u8, @splat(0)); expected[28] = 0xde; expected[29] = 0xad; expected[30] = 0xbe; @@ -381,9 +381,9 @@ test "callWithOverrides applies stateDiff (storage slot)" { // Returns storage slot 5 as a 32-byte word. const bytecode = [_]u8{ 0x60, 0x05, 0x54, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3 }; - var slot = [_]u8{0} ** 32; + var slot = @as([32]u8, @splat(0)); slot[31] = 0x05; - var value = [_]u8{0} ** 32; + var value = @as([32]u8, @splat(0)); value[30] = 0xab; value[31] = 0xcd;