Skip to content

Commit 071bc8e

Browse files
authored
Merge pull request #8 from blockblaz/feature
fix: Handle and parse all fields returned in the JSOn
2 parents 74780bf + fee58d9 commit 071bc8e

File tree

2 files changed

+143
-17
lines changed

2 files changed

+143
-17
lines changed

src/core/errors.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub const SequencerError = error{
2424
L1ConnectionFailed,
2525
L1SubmissionFailed,
2626
L1TransactionReverted,
27+
JsonRpcError,
28+
InvalidJsonRpcVersion,
2729

2830
// State errors
2931
StateCorruption,

src/l1/client.zig

Lines changed: 141 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,35 @@ pub const Client = struct {
130130
const result = try self.callRpc("eth_getTransactionCount", std.json.Value{ .array = params });
131131
defer self.allocator.free(result);
132132

133-
// Parse result
133+
// Parse full JSON-RPC response
134134
const parsed = try std.json.parseFromSliceLeaky(
135-
struct { result: []const u8 },
135+
struct {
136+
jsonrpc: []const u8,
137+
id: std.json.Value,
138+
result: []const u8,
139+
@"error": ?struct {
140+
code: i32,
141+
message: []const u8,
142+
data: ?std.json.Value = null,
143+
} = null,
144+
},
136145
self.allocator,
137146
result,
138-
.{},
147+
.{ .ignore_unknown_fields = true },
139148
);
140149

150+
// Check for error response
151+
if (parsed.@"error") |err| {
152+
std.log.err("[L1Client] eth_getTransactionCount error: code={d}, message={s}", .{ err.code, err.message });
153+
return error.JsonRpcError;
154+
}
155+
156+
// Validate jsonrpc version
157+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
158+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
159+
return error.InvalidJsonRpcVersion;
160+
}
161+
141162
// Convert hex string to u64
142163
const hex_str = parsed.result;
143164
const hex_start: usize = if (std.mem.startsWith(u8, hex_str, "0x")) 2 else 0;
@@ -204,14 +225,35 @@ pub const Client = struct {
204225
const result = try self.callRpc("eth_sendRawTransaction", std.json.Value{ .array = params });
205226
defer self.allocator.free(result);
206227

207-
// Parse result - should be transaction hash
228+
// Parse full JSON-RPC response
208229
const parsed = try std.json.parseFromSliceLeaky(
209-
struct { result: []const u8 },
230+
struct {
231+
jsonrpc: []const u8,
232+
id: std.json.Value,
233+
result: []const u8,
234+
@"error": ?struct {
235+
code: i32,
236+
message: []const u8,
237+
data: ?std.json.Value = null,
238+
} = null,
239+
},
210240
self.allocator,
211241
result,
212-
.{},
242+
.{ .ignore_unknown_fields = true },
213243
);
214244

245+
// Check for error response
246+
if (parsed.@"error") |err| {
247+
std.log.err("[L1Client] eth_sendRawTransaction error: code={d}, message={s}", .{ err.code, err.message });
248+
return error.JsonRpcError;
249+
}
250+
251+
// Validate jsonrpc version
252+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
253+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
254+
return error.InvalidJsonRpcVersion;
255+
}
256+
215257
// Convert hex string to Hash
216258
const hash_str = parsed.result;
217259
const hash_bytes = try self.hexToBytes(hash_str);
@@ -256,14 +298,35 @@ pub const Client = struct {
256298
const result = try self.callRpc("eth_sendRawTransactionConditional", std.json.Value{ .array = params });
257299
defer self.allocator.free(result);
258300

259-
// Parse result - should be transaction hash
301+
// Parse full JSON-RPC response
260302
const parsed = try std.json.parseFromSliceLeaky(
261-
struct { result: []const u8 },
303+
struct {
304+
jsonrpc: []const u8,
305+
id: std.json.Value,
306+
result: []const u8,
307+
@"error": ?struct {
308+
code: i32,
309+
message: []const u8,
310+
data: ?std.json.Value = null,
311+
} = null,
312+
},
262313
self.allocator,
263314
result,
264-
.{},
315+
.{ .ignore_unknown_fields = true },
265316
);
266317

318+
// Check for error response
319+
if (parsed.@"error") |err| {
320+
std.log.err("[L1Client] eth_sendRawTransactionConditional error: code={d}, message={s}", .{ err.code, err.message });
321+
return error.JsonRpcError;
322+
}
323+
324+
// Validate jsonrpc version
325+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
326+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
327+
return error.InvalidJsonRpcVersion;
328+
}
329+
267330
// Convert hex string to Hash
268331
const hash_str = parsed.result;
269332
const hash_bytes = try self.hexToBytes(hash_str);
@@ -316,17 +379,38 @@ pub const Client = struct {
316379
return error.EmptyResponse;
317380
}
318381

319-
// Parse result - should be hex string
382+
// Parse full JSON-RPC response
320383
const parsed = std.json.parseFromSliceLeaky(
321-
struct { result: []const u8 },
384+
struct {
385+
jsonrpc: []const u8,
386+
id: std.json.Value,
387+
result: []const u8,
388+
@"error": ?struct {
389+
code: i32,
390+
message: []const u8,
391+
data: ?std.json.Value = null,
392+
} = null,
393+
},
322394
self.allocator,
323395
result,
324-
.{},
396+
.{ .ignore_unknown_fields = true },
325397
) catch |err| {
326398
std.log.err("[L1Client] Failed to parse eth_blockNumber response: {any}, response: {s}", .{ err, result });
327399
return error.UnexpectedToken;
328400
};
329401

402+
// Check for error response
403+
if (parsed.@"error") |err| {
404+
std.log.err("[L1Client] eth_blockNumber error: code={d}, message={s}", .{ err.code, err.message });
405+
return error.JsonRpcError;
406+
}
407+
408+
// Validate jsonrpc version
409+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
410+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
411+
return error.InvalidJsonRpcVersion;
412+
}
413+
330414
// Convert hex string to u64
331415
const hex_str = parsed.result;
332416
const hex_start: usize = if (std.mem.startsWith(u8, hex_str, "0x")) 2 else 0;
@@ -362,22 +446,41 @@ pub const Client = struct {
362446
const result = try self.callRpc("eth_getBlockByNumber", std.json.Value{ .array = params });
363447
defer self.allocator.free(result);
364448

365-
// Parse result
449+
// Parse full JSON-RPC response
366450
const parsed = try std.json.parseFromSliceLeaky(
367451
struct {
452+
jsonrpc: []const u8,
453+
id: std.json.Value,
368454
result: struct {
369455
number: []const u8,
370456
hash: []const u8,
371457
parentHash: []const u8,
372458
timestamp: []const u8,
373459
transactions: []struct { to: ?[]const u8, input: []const u8 },
374460
},
461+
@"error": ?struct {
462+
code: i32,
463+
message: []const u8,
464+
data: ?std.json.Value = null,
465+
} = null,
375466
},
376467
self.allocator,
377468
result,
378-
.{},
469+
.{ .ignore_unknown_fields = true },
379470
);
380471

472+
// Check for error response
473+
if (parsed.@"error") |err| {
474+
std.log.err("[L1Client] eth_getBlockByNumber error: code={d}, message={s}", .{ err.code, err.message });
475+
return error.JsonRpcError;
476+
}
477+
478+
// Validate jsonrpc version
479+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
480+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
481+
return error.InvalidJsonRpcVersion;
482+
}
483+
381484
const hex_start: usize = if (std.mem.startsWith(u8, parsed.result.number, "0x")) 2 else 0;
382485
const number = try std.fmt.parseInt(u64, parsed.result.number[hex_start..], 16);
383486

@@ -439,14 +542,35 @@ pub const Client = struct {
439542
const result = try self.callRpc("eth_getTransactionReceipt", std.json.Value{ .array = params });
440543
defer self.allocator.free(result);
441544

442-
// Parse result
545+
// Parse full JSON-RPC response
443546
const parsed = try std.json.parseFromSliceLeaky(
444-
struct { result: ?struct { blockNumber: []const u8 } },
547+
struct {
548+
jsonrpc: []const u8,
549+
id: std.json.Value,
550+
result: ?struct { blockNumber: []const u8 },
551+
@"error": ?struct {
552+
code: i32,
553+
message: []const u8,
554+
data: ?std.json.Value = null,
555+
} = null,
556+
},
445557
self.allocator,
446558
result,
447-
.{},
559+
.{ .ignore_unknown_fields = true },
448560
);
449561

562+
// Check for error response
563+
if (parsed.@"error") |err| {
564+
std.log.err("[L1Client] eth_getTransactionReceipt error: code={d}, message={s}", .{ err.code, err.message });
565+
return error.JsonRpcError;
566+
}
567+
568+
// Validate jsonrpc version
569+
if (!std.mem.eql(u8, parsed.jsonrpc, "2.0")) {
570+
std.log.err("[L1Client] Invalid jsonrpc version: {s}", .{parsed.jsonrpc});
571+
return error.InvalidJsonRpcVersion;
572+
}
573+
450574
if (parsed.result) |rec| {
451575
const hex_start: usize = if (std.mem.startsWith(u8, rec.blockNumber, "0x")) 2 else 0;
452576
const block_num = try std.fmt.parseInt(u64, rec.blockNumber[hex_start..], 16);

0 commit comments

Comments
 (0)