Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,10 @@ data/

# Tool versions
.tool-versions

# Local Zig package cache
zig-pkg/

# Shadow network simulator (generated by lean-quickstart/run-shadow.sh)
shadow.yaml
shadow.data/
5 changes: 4 additions & 1 deletion pkgs/cli/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const node_lib = @import("@zeam/node");
const Clock = node_lib.Clock;
const state_proving_manager = @import("@zeam/state-proving-manager");
const BeamNode = node_lib.BeamNode;
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const Multiaddr = @import("multiaddr").Multiaddr;

const configs = @import("@zeam/configs");
Expand Down Expand Up @@ -281,6 +281,9 @@ fn mainInner() !void {

std.debug.print("opts={any} genesis={d}\n", .{ opts.args, genesis });

// Detect the best available I/O backend (io_uring or epoll on Linux).
node_lib.detectBackend();
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node_lib.detectBackend() currently panics on failure (see utils.detectBackend), which bypasses the CLI’s normal ErrorHandler flow and will crash the process with a generic message. Consider changing detection to return an error and handling/logging it here (similar to the xev.Loop.init error handling below) so startup failures are reported consistently.

Suggested change
node_lib.detectBackend();
node_lib.detectBackend() catch |err| {
ErrorHandler.logErrorWithOperation(err, "detect I/O backend");
return err;
};

Copilot uses AI. Check for mistakes.

switch (opts.args.__commands__) {
.clock => {
var loop = xev.Loop.init(.{}) catch |err| {
Expand Down
2 changes: 1 addition & 1 deletion pkgs/cli/src/node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ChainConfig = configs.ChainConfig;
const Chain = configs.Chain;
const ChainOptions = configs.ChainOptions;
const sft = @import("@zeam/state-transition");
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const networks = @import("@zeam/network");
const Multiaddr = @import("multiaddr").Multiaddr;
const node_lib = @import("@zeam/node");
Expand Down
2 changes: 1 addition & 1 deletion pkgs/network/src/ethlibp2p.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const Thread = std.Thread;

const ssz = @import("ssz");
const types = @import("@zeam/types");
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const multiformats = @import("multiformats");
const multiaddr_mod = @import("multiaddr");
const Multiaddr = multiaddr_mod.Multiaddr;
Expand Down
2 changes: 1 addition & 1 deletion pkgs/network/src/interface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const json = std.json;

const types = @import("@zeam/types");
const ssz = @import("ssz");
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const zeam_utils = @import("@zeam/utils");
const consensus_params = @import("@zeam/params");

Expand Down
4 changes: 3 additions & 1 deletion pkgs/network/src/mock.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator;

const types = @import("@zeam/types");
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const zeam_utils = @import("@zeam/utils");

const interface = @import("./interface.zig");
Expand Down Expand Up @@ -774,6 +774,7 @@ test "Mock messaging across two subscribers" {
defer arena_allocator.deinit();
const allocator = arena_allocator.allocator();

if (@hasDecl(xev, "detect")) xev.detect() catch @panic("no available xev backend");
var loop = try xev.Loop.init(.{});
Comment on lines +777 to 778
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if (@hasDecl(xev, "detect")) xev.detect() ... backend-detection snippet is duplicated in multiple tests in this file. Consider factoring it into a small local helper (e.g., detectBackendOrPanic()), so the behavior/error handling stays consistent and future changes only need to be made once.

Copilot uses AI. Check for mistakes.
defer loop.deinit();

Expand Down Expand Up @@ -954,6 +955,7 @@ test "Mock status RPC between peers" {
defer arena_allocator.deinit();
const allocator = arena_allocator.allocator();

if (@hasDecl(xev, "detect")) xev.detect() catch @panic("no available xev backend");
var loop = try xev.Loop.init(.{});
defer loop.deinit();
Comment on lines +958 to 960
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This backend detection line duplicates the same xev.detect() snippet used earlier in this file. To reduce repetition (and keep the panic/error message consistent), consider extracting the detection into a single helper and calling it from each test before xev.Loop.init.

Copilot uses AI. Check for mistakes.

Expand Down
2 changes: 1 addition & 1 deletion pkgs/node/src/clock.zig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const std = @import("std");
const Allocator = std.mem.Allocator;

const xev = @import("xev");
const xev = @import("xev").Dynamic;

const constants = @import("./constants.zig");

Expand Down
1 change: 1 addition & 0 deletions pkgs/node/src/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub const fcFactory = @import("./forkchoice.zig");
pub const tree_visualizer = @import("./tree_visualizer.zig");
pub const constants = @import("./constants.zig");
pub const utils = @import("./utils.zig");
pub const detectBackend = utils.detectBackend;

const networks = @import("@zeam/network");
pub const NodeNameRegistry = networks.NodeNameRegistry;
Expand Down
2 changes: 1 addition & 1 deletion pkgs/node/src/node.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,7 @@ pub const BeamNode = struct {
}
};

const xev = @import("xev");
const xev = @import("xev").Dynamic;

test "Node peer tracking on connect/disconnect" {
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
Expand Down
5 changes: 4 additions & 1 deletion pkgs/node/src/testing.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const key_manager = @import("@zeam/key-manager");
const params = @import("@zeam/params");
const types = @import("@zeam/types");
const zeam_utils = @import("@zeam/utils");
const xev = @import("xev");
const xev = @import("xev").Dynamic;
const networks = @import("@zeam/network");
const xmss = @import("@zeam/xmss");
const clockFactory = @import("./clock.zig");
Expand Down Expand Up @@ -47,6 +47,9 @@ pub const NodeTestContext = struct {
spec_name_owned: bool = true,

pub fn init(allocator: Allocator, opts: NodeTestOptions) !NodeTestContext {
const utils = @import("./utils.zig");
utils.detectBackend();

var loop = try xev.Loop.init(.{});
errdefer loop.deinit();

Expand Down
11 changes: 10 additions & 1 deletion pkgs/node/src/utils.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ const std = @import("std");
const Thread = std.Thread;
const Mutex = Thread.Mutex;

const xev = @import("xev");
const xev = @import("xev").Dynamic;
const types = @import("@zeam/types");

/// Detect the best available I/O backend at runtime.
/// On Linux this probes io_uring, falling back to epoll (needed for Shadow).
/// On single-backend platforms (macOS/kqueue) this is a no-op.
pub fn detectBackend() void {
if (@hasDecl(xev, "detect")) {
xev.detect() catch @panic("no available xev backend");
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xev.detect() failures are turned into a generic @panic("no available xev backend"), which drops the underlying error and makes field debugging hard (e.g., missing io_uring support vs. permission issues). Consider including the caught error (e.g., @errorName(err) / {any}) in the panic message or returning an error instead of panicking so callers can surface it consistently.

Suggested change
xev.detect() catch @panic("no available xev backend");
xev.detect() catch |err| std.debug.panic("no available xev backend: {s}", .{@errorName(err)});

Copilot uses AI. Check for mistakes.
}
}

pub const EventLoop = struct {
loop: *xev.Loop,
// events from libp2p or other threads will also be pushed on it
Expand Down
Loading