Skip to content

Commit fb9c95f

Browse files
authored
Merge pull request #14 from optimism-java/testcases
feat: add ssz test for more types
2 parents dce7654 + f72568e commit fb9c95f

File tree

2 files changed

+99
-32
lines changed

2 files changed

+99
-32
lines changed

src/spec_tests/ssz_static/root.zig

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ const Yaml = @import("../../yaml/yaml.zig").Yaml;
99
const gpa = testing.allocator;
1010

1111
/// Loads and parses a YAML file into a Yaml object
12-
/// Parameters:
13-
/// file_path: Path to the YAML file to load
14-
/// Returns:
15-
/// Parsed Yaml object or error
1612
fn loadFromFile(file_path: []const u8) !Yaml {
1713
const file = try std.fs.cwd().openFile(file_path, .{});
1814
defer file.close();
@@ -26,42 +22,101 @@ fn loadFromFile(file_path: []const u8) !Yaml {
2622
const Roots = struct {
2723
root: [32]u8,
2824
};
25+
26+
const StructMultiPhase = union {
27+
Attestation: types.Attestation,
28+
BeaconBlockBody: types.BeaconBlockBody,
29+
BeaconState: types.BeaconState,
30+
BlobIdentifier: types.BlobIdentifier,
31+
BlobSidecar: types.BlobSidecar,
32+
BLSToExecutionChange: types.BLSToExecutionChange,
33+
ConsolidationRequest: types.ConsolidationRequest,
34+
ContributionAndProof: types.ContributionAndProof,
35+
DepositRequest: types.DepositRequest,
36+
ExecutionPayload: types.ExecutionPayload,
37+
ExecutionPayloadHeader: types.ExecutionPayloadHeader,
38+
HistoricalSummary: types.HistoricalSummary,
39+
LightClientBootstrap: types.LightClientBootstrap,
40+
LightClientFinalityUpdate: types.LightClientFinalityUpdate,
41+
LightClientHeader: types.LightClientHeader,
42+
LightClientOptimisticUpdate: types.LightClientOptimisticUpdate,
43+
LightClientUpdate: types.LightClientUpdate,
44+
PendingBalanceDeposit: types.PendingBalanceDeposit,
45+
PendingConsolidation: types.PendingConsolidation,
46+
PendingPartialWithdrawal: types.PendingPartialWithdrawal,
47+
PowBlock: types.PowBlock,
48+
SignedBLSToExecutionChange: types.SignedBLSToExecutionChange,
49+
SignedContributionAndProof: types.SignedContributionAndProof,
50+
SignedVoluntaryExit: types.SignedVoluntaryExit,
51+
SyncAggregate: types.SyncAggregate,
52+
SyncCommittee: types.SyncCommittee,
53+
SyncCommitteeContribution: types.SyncCommitteeContribution,
54+
SyncCommitteeMessage: types.SyncCommitteeMessage,
55+
Withdrawal: types.Withdrawal,
56+
WithdrawalRequest: types.WithdrawalRequest,
57+
};
58+
2959
// test cases for all phases
3060
const CommonUnion = union {
61+
// AggregateAndProof: types.AggregateAndProof,
62+
// AttestationData: types.AttestationData,
63+
// AttesterSlashing: types.AttesterSlashing,
64+
// BeaconBlock: types.BeaconBlock,
65+
// BeaconBlockHeader: types.BeaconBlockHeader,
66+
Checkpoint: types.Checkpoint,
67+
// Deposit: types.Deposit,
68+
// DepositData: types.DepositData,
69+
// DepositMessage: types.DepositMessage,
70+
// Eth1Block: types.Eth1Block,
71+
// Eth1Data: types.Eth1Data,
3172
Fork: types.Fork,
73+
ForkData: types.ForkData,
74+
// HistoricalBatch: types.HistoricalBatch,
75+
// IndexedAttestation: types.IndexedAttestation,
76+
// PendingAttestation: types.PendingAttestation,
77+
// ProposerSlashing: types.ProposerSlashing,
78+
// SignedBeaconBlock: types.SignedBeaconBlock,
79+
// SignedBeaconBlockHeader: types.SignedBeaconBlockHeader,
80+
// SigningData: types.SigningData,
81+
SyncAggregatorSelectionData: types.SyncAggregatorSelectionData, // only exist in altair or later
82+
// Validator: types.Validator,
83+
VoluntaryExit: types.VoluntaryExit,
3284
};
3385

86+
const forkDirs = [_][]const u8{ "phase0", "altair", "bellatrix", "capella", "deneb", "electra" };
87+
3488
test "ssz static" {
3589
const testPath = "consensus-spec-tests/tests/mainnet";
3690
const gpa1 = testing.allocator;
3791
const fields = @typeInfo(CommonUnion).@"union".fields;
3892
inline for (fields) |field| {
3993
const fieldType = field.type;
4094
const fieldName = field.name;
41-
const ssz_type_path = try std.fmt.allocPrint(gpa1, "{s}/phase0/ssz_static/{s}", .{ testPath, fieldName });
42-
43-
var dirs = try getLeafDirs(gpa1, ssz_type_path);
44-
45-
// deinit the dirs array
46-
defer {
47-
for (dirs.items) |item| {
48-
gpa1.free(item);
95+
for (forkDirs) |fork| {
96+
const ssz_type_path = try std.fmt.allocPrint(gpa1, "{s}/{s}/ssz_static/{s}", .{ testPath, fork, fieldName });
97+
98+
var dirs = getLeafDirs(gpa1, ssz_type_path) catch |err| {
99+
if (err == error.FileNotFound) {
100+
continue;
101+
}
102+
return err;
103+
};
104+
// deinit the dirs array
105+
defer {
106+
for (dirs.items) |item| {
107+
gpa1.free(item);
108+
}
109+
dirs.deinit();
49110
}
50-
dirs.deinit();
51-
}
52111

53-
for (dirs.items) |dir| {
54-
try testSSZStatic(dir, fieldType);
112+
for (dirs.items) |dir| {
113+
try testSSZStatic(dir, fieldType);
114+
}
55115
}
56116
}
57117
}
58118

59119
/// Recursively finds all leaf directories (directories with no subdirectories) starting from the given path
60-
/// Parameters:
61-
/// allocator: Memory allocator for dynamic allocations
62-
/// path: Starting directory path to search from
63-
/// Returns:
64-
/// ArrayList containing paths to all leaf directories
65120
fn getLeafDirs(allocator: std.mem.Allocator, path: []const u8) !std.ArrayList([]const u8) {
66121
var leafDirs = std.ArrayList([]const u8).init(allocator);
67122
// defer leafDirs.deinit();
@@ -101,12 +156,6 @@ fn getLeafDirs(allocator: std.mem.Allocator, path: []const u8) !std.ArrayList([]
101156
}
102157

103158
/// Tests SSZ (Simple Serialize) static functionality by performing:
104-
/// 1. YAML parsing
105-
/// 2. Hash tree root verification
106-
/// 3. SSZ encoding/decoding with snappy compression
107-
/// Parameters:
108-
/// path: Directory path containing test files
109-
/// t: Type to test SSZ operations against
110159
fn testSSZStatic(path: []const u8, t: type) !void {
111160
// parse from yaml
112161
const valueFile = try std.fmt.allocPrint(testing.allocator, "{s}/value.yaml", .{path});

src/yaml/yaml.zig

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//! The code bellow is essentially a port of https://github.com/kubkon/zig-yaml
2-
31
const std = @import("std");
42
const assert = std.debug.assert;
53
const math = std.math;
@@ -29,6 +27,7 @@ pub const Map = std.StringArrayHashMap(Value);
2927
pub const Value = union(enum) {
3028
empty,
3129
int: i64,
30+
uint: u64,
3231
float: f64,
3332
string: []const u8,
3433
list: List,
@@ -39,6 +38,11 @@ pub const Value = union(enum) {
3938
return self.int;
4039
}
4140

41+
pub fn asUint(self: Value) !u64 {
42+
if (self != .uint) return error.TypeMismatch;
43+
return self.uint;
44+
}
45+
4246
pub fn asFloat(self: Value) !f64 {
4347
if (self != .float) return error.TypeMismatch;
4448
return self.float;
@@ -90,6 +94,7 @@ pub const Value = union(enum) {
9094
switch (self) {
9195
.empty => return,
9296
.int => |int| return writer.print("{}", .{int}),
97+
.uint => |uint| return writer.print("{}", .{uint}),
9398
.float => |float| return writer.print("{d}", .{float}),
9499
.string => |string| return writer.print("{s}", .{string}),
95100
.list => |list| {
@@ -205,8 +210,15 @@ pub const Value = union(enum) {
205210
const raw = tree.getRaw(node.start, node.end);
206211

207212
try_int: {
208-
const int = std.fmt.parseInt(i64, raw, 0) catch break :try_int;
209-
return Value{ .int = int };
213+
if (std.fmt.parseUnsigned(u64, raw, 0)) |uint| {
214+
if (uint > math.maxInt(i64)) {
215+
return Value{ .uint = uint };
216+
}
217+
return Value{ .int = @intCast(uint) };
218+
} else |_| {
219+
const int = std.fmt.parseInt(i64, raw, 0) catch break :try_int;
220+
return Value{ .int = int };
221+
}
210222
}
211223

212224
try_float: {
@@ -393,7 +405,13 @@ pub const Yaml = struct {
393405

394406
fn parseValue(self: *Yaml, comptime T: type, value: Value) Error!T {
395407
return switch (@typeInfo(T)) {
396-
.int => math.cast(T, try value.asInt()) orelse return error.Overflow,
408+
.int => {
409+
return switch (value) {
410+
.int => math.cast(T, try value.asInt()) orelse return error.Overflow,
411+
.uint => math.cast(T, try value.asUint()) orelse return error.Overflow,
412+
else => return error.TypeMismatch,
413+
};
414+
},
397415
.float => if (value.asFloat()) |float| {
398416
return math.lossyCast(T, float);
399417
} else |_| {

0 commit comments

Comments
 (0)