diff --git a/.gitignore b/.gitignore index 360adcc5..3b692ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/pkgs/cli/src/main.zig b/pkgs/cli/src/main.zig index caf9478f..4e8cd524 100644 --- a/pkgs/cli/src/main.zig +++ b/pkgs/cli/src/main.zig @@ -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"); @@ -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(); + switch (opts.args.__commands__) { .clock => { var loop = xev.Loop.init(.{}) catch |err| { diff --git a/pkgs/cli/src/node.zig b/pkgs/cli/src/node.zig index 594ad253..97ce9c2f 100644 --- a/pkgs/cli/src/node.zig +++ b/pkgs/cli/src/node.zig @@ -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"); diff --git a/pkgs/network/src/ethlibp2p.zig b/pkgs/network/src/ethlibp2p.zig index 9e8343e7..8fcdee56 100644 --- a/pkgs/network/src/ethlibp2p.zig +++ b/pkgs/network/src/ethlibp2p.zig @@ -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; diff --git a/pkgs/network/src/interface.zig b/pkgs/network/src/interface.zig index d4cb1a6b..44f5b4e9 100644 --- a/pkgs/network/src/interface.zig +++ b/pkgs/network/src/interface.zig @@ -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"); diff --git a/pkgs/network/src/mock.zig b/pkgs/network/src/mock.zig index bf776d5f..ee879779 100644 --- a/pkgs/network/src/mock.zig +++ b/pkgs/network/src/mock.zig @@ -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"); @@ -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(.{}); defer loop.deinit(); @@ -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(); diff --git a/pkgs/node/src/clock.zig b/pkgs/node/src/clock.zig index 33a2b257..d3b43e5a 100644 --- a/pkgs/node/src/clock.zig +++ b/pkgs/node/src/clock.zig @@ -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"); diff --git a/pkgs/node/src/lib.zig b/pkgs/node/src/lib.zig index e546f118..9879398d 100644 --- a/pkgs/node/src/lib.zig +++ b/pkgs/node/src/lib.zig @@ -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; diff --git a/pkgs/node/src/node.zig b/pkgs/node/src/node.zig index 97799aba..d012a5cd 100644 --- a/pkgs/node/src/node.zig +++ b/pkgs/node/src/node.zig @@ -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); diff --git a/pkgs/node/src/testing.zig b/pkgs/node/src/testing.zig index 46449ed4..daa2fc91 100644 --- a/pkgs/node/src/testing.zig +++ b/pkgs/node/src/testing.zig @@ -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"); @@ -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(); diff --git a/pkgs/node/src/utils.zig b/pkgs/node/src/utils.zig index 862de052..ceaac3dd 100644 --- a/pkgs/node/src/utils.zig +++ b/pkgs/node/src/utils.zig @@ -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"); + } +} + pub const EventLoop = struct { loop: *xev.Loop, // events from libp2p or other threads will also be pushed on it