-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path10_error_handling.zig
More file actions
279 lines (232 loc) Β· 13.9 KB
/
Copy path10_error_handling.zig
File metadata and controls
279 lines (232 loc) Β· 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
const std = @import("std");
const zigeth = @import("zigeth");
/// Example: Comprehensive Error Handling in Zigeth
/// Demonstrates best practices for error handling, formatting, and reporting
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("\n", .{});
std.debug.print("=" ** 80 ++ "\n", .{});
std.debug.print(" Zigeth Error Handling - Best Practices\n", .{});
std.debug.print("=" ** 80 ++ "\n\n", .{});
// ============================================================================
// EXAMPLE 1: Basic Error Context
// ============================================================================
try example1_basic_error_context(allocator);
// ============================================================================
// EXAMPLE 2: Error Formatting (JSON, Text, Log)
// ============================================================================
try example2_error_formatting(allocator);
// ============================================================================
// EXAMPLE 3: RPC Error Handling
// ============================================================================
try example3_rpc_errors(allocator);
// ============================================================================
// EXAMPLE 4: Transaction Error Handling
// ============================================================================
try example4_transaction_errors(allocator);
// ============================================================================
// EXAMPLE 5: Error Recovery Patterns
// ============================================================================
try example5_error_recovery(allocator);
// ============================================================================
// EXAMPLE 6: Production Error Reporting
// ============================================================================
try example6_production_reporting(allocator);
std.debug.print("\n", .{});
std.debug.print("=" ** 80 ++ "\n", .{});
std.debug.print(" β
All Error Handling Examples Complete!\n", .{});
std.debug.print("=" ** 80 ++ "\n\n", .{});
}
fn example1_basic_error_context(allocator: std.mem.Allocator) !void {
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 1: Basic Error Context β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
// Create error context
const ctx = zigeth.ErrorContext.init("RPC", "eth_getBlockByNumber");
const ctx_with_details = ctx.withDetails("Block 999999999 not found");
const ctx_with_code = ctx_with_details.withCode(-32000);
std.debug.print("β
Error Context Created:\n", .{});
std.debug.print(" β’ Module: {s}\n", .{ctx_with_code.module});
std.debug.print(" β’ Operation: {s}\n", .{ctx_with_code.operation});
std.debug.print(" β’ Details: {s}\n", .{ctx_with_code.details.?});
std.debug.print(" β’ Code: {}\n\n", .{ctx_with_code.code.?});
// Format the error
const formatted = try zigeth.errors.formatError(allocator, error.BlockNotFound, ctx_with_code);
defer allocator.free(formatted);
std.debug.print("π Formatted Error:\n{s}\n", .{formatted});
}
fn example2_error_formatting(allocator: std.mem.Allocator) !void {
std.debug.print("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 2: Error Formatting (JSON, Text, Log) β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
const ctx = zigeth.ErrorContext.init("Provider", "getBalance")
.withDetails("RPC endpoint unreachable")
.withCode(-1);
const formatter = zigeth.ErrorFormatter.init(allocator, true); // with colors
// JSON format (for APIs)
const json = try formatter.toJson(error.NetworkError, ctx);
defer allocator.free(json);
std.debug.print("π JSON Format (for APIs):\n", .{});
std.debug.print("{s}\n\n", .{json});
// Text format (for CLI/user display)
const text = try formatter.toText(error.NetworkError, ctx);
defer allocator.free(text);
std.debug.print("π Text Format (for CLI/user display):\n", .{});
std.debug.print("{s}\n", .{text});
// Log format (for log files)
const log_entry = try formatter.toLog(error.NetworkError, ctx);
defer allocator.free(log_entry);
std.debug.print("π Log Format (for log files):\n", .{});
std.debug.print("{s}\n\n", .{log_entry});
// User-friendly message
const user_msg = zigeth.errors.Helpers.getUserMessage(error.NetworkError);
std.debug.print("π¬ User-Friendly Message:\n", .{});
std.debug.print(" {s}\n", .{user_msg});
}
fn example3_rpc_errors(allocator: std.mem.Allocator) !void {
std.debug.print("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 3: RPC Error Handling β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
std.debug.print("β
Module-Specific Error Sets:\n\n", .{});
// Demonstrate RPC errors
std.debug.print("π‘ RPC Errors:\n", .{});
const rpc_errors = [_]zigeth.RpcErrors{
error.ConnectionFailed,
error.Timeout,
error.InvalidJsonRpcResponse,
error.JsonRpcError,
};
for (rpc_errors) |err| {
const ctx = zigeth.ErrorContext.init("RPC", "call");
const formatted = try zigeth.errors.formatError(allocator, err, ctx);
defer allocator.free(formatted);
std.debug.print(" β’ {s}: {s}\n", .{ @errorName(err), zigeth.errors.Helpers.getUserMessage(err) });
}
std.debug.print("\nπΌ Wallet Errors:\n", .{});
const wallet_errors = [_]zigeth.WalletErrors{
error.InvalidPrivateKey,
error.InvalidMnemonic,
error.InvalidKeystore,
};
for (wallet_errors) |err| {
std.debug.print(" β’ {s}: {s}\n", .{ @errorName(err), zigeth.errors.Helpers.getUserMessage(err) });
}
std.debug.print("\nπ Contract Errors:\n", .{});
const contract_errors = [_]zigeth.ContractErrors{
error.ContractNotFound,
error.ContractCallFailed,
error.AbiEncodingFailed,
};
for (contract_errors) |err| {
std.debug.print(" β’ {s}: {s}\n", .{ @errorName(err), zigeth.errors.Helpers.getUserMessage(err) });
}
}
fn example4_transaction_errors(allocator: std.mem.Allocator) !void {
std.debug.print("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 4: Transaction Error Handling β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
// Simulate transaction errors
std.debug.print("β
Common Transaction Errors:\n\n", .{});
const tx_errors = [_]struct {
err: zigeth.TransactionErrors,
description: []const u8,
}{
.{ .err = error.InsufficientFunds, .description = "Sender doesn't have enough ETH" },
.{ .err = error.NonceTooLow, .description = "Nonce already used" },
.{ .err = error.GasTooLow, .description = "Gas limit too low for execution" },
.{ .err = error.TransactionUnderpriced, .description = "Gas price too low" },
.{ .err = error.InvalidSignature, .description = "Signature verification failed" },
};
for (tx_errors) |item| {
const ctx = zigeth.ErrorContext.init("Transaction", "send")
.withDetails(item.description);
const formatted = try zigeth.errors.formatError(allocator, item.err, ctx);
defer allocator.free(formatted);
std.debug.print("{s}\n", .{formatted});
std.debug.print(" β User message: {s}\n\n", .{
zigeth.errors.Helpers.getUserMessage(item.err),
});
}
}
fn example5_error_recovery(allocator: std.mem.Allocator) !void {
_ = allocator;
std.debug.print("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 5: Error Recovery Patterns β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
std.debug.print("β
Error Classification:\n\n", .{});
// Test error classification
const test_errors = [_]anyerror{
error.NetworkError,
error.Timeout,
error.InvalidAddress,
error.InsufficientFunds,
};
for (test_errors) |err| {
std.debug.print("Error: {s}\n", .{@errorName(err)});
std.debug.print(" β’ Network error? {}\n", .{zigeth.errors.Helpers.isNetworkError(err)});
std.debug.print(" β’ RPC error? {}\n", .{zigeth.errors.Helpers.isRpcError(err)});
std.debug.print(" β’ Validation error? {}\n", .{zigeth.errors.Helpers.isValidationError(err)});
std.debug.print(" β’ Retryable? {}\n\n", .{zigeth.errors.Helpers.isRetryable(err)});
}
std.debug.print("π‘ Usage in code:\n", .{});
std.debug.print("```zig\n", .{});
std.debug.print("if (zigeth.errors.Helpers.isRetryable(err)) {{\n", .{});
std.debug.print(" // Retry with exponential backoff\n", .{});
std.debug.print(" return zigeth.errors.ErrorRecovery.retryWithBackoff(...);\n", .{});
std.debug.print("}}\n", .{});
std.debug.print("```\n", .{});
}
fn example6_production_reporting(allocator: std.mem.Allocator) !void {
std.debug.print("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n", .{});
std.debug.print("β EXAMPLE 6: Production Error Reporting β\n", .{});
std.debug.print("βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ\n\n", .{});
std.debug.print("β
Production Error Reporter:\n\n", .{});
// Initialize error reporter (in production, open actual log file)
var reporter = zigeth.ErrorReporter.init(allocator, null);
defer reporter.deinit();
// Report various errors
const errors_to_report = [_]struct {
err: anyerror,
module: []const u8,
operation: []const u8,
details: []const u8,
}{
.{
.err = error.ConnectionFailed,
.module = "Provider",
.operation = "connect",
.details = "Failed to connect to https://sepolia.etherspot.io",
},
.{
.err = error.InvalidSignature,
.module = "Transaction",
.operation = "verify",
.details = "ECDSA signature verification failed",
},
.{
.err = error.PaymasterRejected,
.module = "AccountAbstraction",
.operation = "sponsorUserOperation",
.details = "Paymaster rejected: insufficient deposit",
},
};
std.debug.print("Simulated error reports:\n\n", .{});
for (errors_to_report, 1..) |item, i| {
const ctx = zigeth.ErrorContext.init(item.module, item.operation)
.withDetails(item.details);
std.debug.print("{}. ", .{i});
try reporter.report(item.err, ctx);
std.debug.print("\n", .{});
}
std.debug.print("\nπ‘ In production:\n", .{});
std.debug.print("```zig\n", .{});
std.debug.print("// Open log file\n", .{});
std.debug.print("const log_file = try std.fs.cwd().createFile(\"zigeth.log\", .{{}});\n", .{});
std.debug.print("var reporter = zigeth.ErrorReporter.init(allocator, log_file);\n", .{});
std.debug.print("defer reporter.deinit();\n\n", .{});
std.debug.print("// Report errors (will write to file + stderr)\n", .{});
std.debug.print("try reporter.report(err, context);\n", .{});
std.debug.print("```\n", .{});
}