Skip to content

Commit 1ffbcf9

Browse files
fearlessfePengZhen
authored andcommitted
feat: add ssz test for more types
1 parent dce7654 commit 1ffbcf9

File tree

2 files changed

+105
-34
lines changed

2 files changed

+105
-34
lines changed

src/spec_tests/ssz_static/root.zig

Lines changed: 82 additions & 29 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,105 @@ 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+
59+
const altair = union {
60+
SyncAggregatorSelectionData: types.SyncAggregatorSelectionData,
61+
};
62+
2963
// test cases for all phases
30-
const CommonUnion = union {
64+
const commonUnion = union {
65+
// AggregateAndProof: types.AggregateAndProof,
66+
// AttestationData: types.AttestationData,
67+
// AttesterSlashing: types.AttesterSlashing,
68+
// BeaconBlock: types.BeaconBlock,
69+
// BeaconBlockHeader: types.BeaconBlockHeader,
70+
Checkpoint: types.Checkpoint,
71+
// Deposit: types.Deposit,
72+
// DepositData: types.DepositData,
73+
// DepositMessage: types.DepositMessage,
74+
// Eth1Block: types.Eth1Block,
75+
// Eth1Data: types.Eth1Data,
3176
Fork: types.Fork,
77+
ForkData: types.ForkData,
78+
// HistoricalBatch: types.HistoricalBatch,
79+
// IndexedAttestation: types.IndexedAttestation,
80+
// PendingAttestation: types.PendingAttestation,
81+
// ProposerSlashing: types.ProposerSlashing,
82+
// SignedBeaconBlock: types.SignedBeaconBlock,
83+
// SignedBeaconBlockHeader: types.SignedBeaconBlockHeader,
84+
// SigningData: types.SigningData,
85+
SyncAggregatorSelectionData: types.SyncAggregatorSelectionData, // only exist in altair or later
86+
// Validator: types.Validator,
87+
VoluntaryExit: types.VoluntaryExit,
3288
};
3389

90+
const forks = [_][]const u8{ "phase0", "altair", "bellatrix", "capella", "deneb", "electra" };
91+
3492
test "ssz static" {
3593
const testPath = "consensus-spec-tests/tests/mainnet";
3694
const gpa1 = testing.allocator;
37-
const fields = @typeInfo(CommonUnion).@"union".fields;
95+
const fields = @typeInfo(commonUnion).@"union".fields;
3896
inline for (fields) |field| {
3997
const fieldType = field.type;
4098
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);
99+
for (forks) |fork| {
100+
const ssz_type_path = try std.fmt.allocPrint(gpa1, "{s}/{s}/ssz_static/{s}", .{ testPath, fork, fieldName });
101+
102+
var dirs = getLeafDirs(gpa1, ssz_type_path) catch |err| {
103+
if (err == error.FileNotFound) {
104+
continue;
105+
}
106+
return err;
107+
};
108+
// deinit the dirs array
109+
defer {
110+
for (dirs.items) |item| {
111+
gpa1.free(item);
112+
}
113+
dirs.deinit();
49114
}
50-
dirs.deinit();
51-
}
52115

53-
for (dirs.items) |dir| {
54-
try testSSZStatic(dir, fieldType);
116+
for (dirs.items) |dir| {
117+
try testSSZStatic(dir, fieldType);
118+
}
55119
}
56120
}
57121
}
58122

59123
/// 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
65124
fn getLeafDirs(allocator: std.mem.Allocator, path: []const u8) !std.ArrayList([]const u8) {
66125
var leafDirs = std.ArrayList([]const u8).init(allocator);
67126
// defer leafDirs.deinit();
@@ -101,12 +160,6 @@ fn getLeafDirs(allocator: std.mem.Allocator, path: []const u8) !std.ArrayList([]
101160
}
102161

103162
/// 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
110163
fn testSSZStatic(path: []const u8, t: type) !void {
111164
// parse from yaml
112165
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)