diff --git a/bindings/napi/BeaconStateView.zig b/bindings/napi/BeaconStateView.zig index b6a758333..2cdd4748e 100644 --- a/bindings/napi/BeaconStateView.zig +++ b/bindings/napi/BeaconStateView.zig @@ -72,7 +72,7 @@ pub const js_meta = js.class(.{ .properties = .{ } }); cached_state: ?*CachedBeaconState = null, -pool_rc: ?*pool.PoolRc = null, +pool_rc: @TypeOf(pool.state.pool_rc) = null, const BeaconStateView = @This(); pub fn init() BeaconStateView { diff --git a/bindings/napi/blst.zig b/bindings/napi/blst.zig index c48298e78..780f70d2f 100644 --- a/bindings/napi/blst.zig +++ b/bindings/napi/blst.zig @@ -39,25 +39,31 @@ const BATCH_VERIFY_SIZE = 32; /// Initialized lazily on first use, torn down via `deinitThreadPool`. var thread_pool: ?*ThreadPool = null; -pub fn initThreadPool(n_workers: u16) !void { - if (thread_pool != null) return error.PoolExists; - thread_pool = try ThreadPool.init(std.heap.page_allocator, napi_io.get(), .{ .n_workers = n_workers }); -} +/// Native-only thread pool lifecycle, reached from `root.zig` through the +/// pub `lifecycle` var so it is not part of the JS module surface. +const Lifecycle = struct { + pub fn initThreadPool(_: *Lifecycle, n_workers: u16) !void { + if (thread_pool != null) return error.PoolExists; + thread_pool = try ThreadPool.init(std.heap.page_allocator, napi_io.get(), .{ .n_workers = n_workers }); + } -/// Closes the `ThreadPool` used for blst operations. -/// -/// Note: this can invalidate any inflight verification requests. Consumer is responsible -/// for the lifecycle of their program and should only call this when all work is done. -/// -/// This note is however application dependent. For the use case of lodestar, -/// it's likely that this would not be called at all. -/// Same goes for any other long-lived processes. -pub fn deinitThreadPool() void { - if (thread_pool) |p| { - p.deinit(napi_io.get()); - thread_pool = null; + /// Closes the `ThreadPool` used for blst operations. + /// + /// Note: this can invalidate any inflight verification requests. Consumer is responsible + /// for the lifecycle of their program and should only call this when all work is done. + /// + /// This note is however application dependent. For the use case of lodestar, + /// it's likely that this would not be called at all. + /// Same goes for any other long-lived processes. + pub fn deinitThreadPool(_: *Lifecycle) void { + if (thread_pool) |p| { + p.deinit(napi_io.get()); + thread_pool = null; + } } -} +}; + +pub var lifecycle: Lifecycle = .{}; var gpa: std.heap.DebugAllocator(.{}) = .init; const allocator = if (builtin.mode == .Debug) diff --git a/bindings/napi/config.zig b/bindings/napi/config.zig index 0132bd02f..a59092fe3 100644 --- a/bindings/napi/config.zig +++ b/bindings/napi/config.zig @@ -9,7 +9,7 @@ const Preset = @import("preset").Preset; const max_blob_schedule_entries = 16; -pub const State = struct { +const State = struct { config: BeaconConfig = undefined, initialized: bool = false, config_name: [64]u8 = undefined, @@ -71,7 +71,7 @@ pub fn set(object: js.Value, genesis_root: js.Uint8Array) !void { state.initialized = true; } -pub fn chainConfigFromObject(env: napi.Env, obj: napi.Value) !ChainConfig { +fn chainConfigFromObject(env: napi.Env, obj: napi.Value) !ChainConfig { var chain_config: ChainConfig = undefined; inline for (std.meta.fields(ChainConfig)) |field| { diff --git a/bindings/napi/pool.zig b/bindings/napi/pool.zig index 2e0ec480b..c23dcec40 100644 --- a/bindings/napi/pool.zig +++ b/bindings/napi/pool.zig @@ -9,14 +9,14 @@ const allocator = std.heap.page_allocator; const default_pool_size: u32 = 0; -pub const PoolRc = RefCount(Node.Pool); +const PoolRc = RefCount(Node.Pool); /// Pool is wrapped in `RefCount` so binding objects holding pool refs at /// process exit keep the pool alive until their JS finalizer runs. NAPI /// env cleanup hook fires before module-level JS holders are finalized, /// so an unconditional `pool.deinit()` there would free memory that /// `pool.unref()` calls in those finalizers still need. -pub const State = struct { +const State = struct { pool_rc: ?*PoolRc = null, pub fn init(self: *State) !void { diff --git a/bindings/napi/pubkeys.zig b/bindings/napi/pubkeys.zig index 86e611682..79a25f2f4 100644 --- a/bindings/napi/pubkeys.zig +++ b/bindings/napi/pubkeys.zig @@ -19,7 +19,7 @@ const max_stack_aggregate_pubkeys = 512; /// per epoch at 12s slots), so growth stays proportionate at any network scale. const growth_step: u32 = preset.MAX_PENDING_DEPOSITS_PER_EPOCH * ((90 * 24 * 60 * 60) / (12 * preset.SLOTS_PER_EPOCH)); -pub const State = struct { +const State = struct { pubkey2index: PubkeyIndexMap = undefined, index2pubkey: Index2PubkeyCache = undefined, initialized: bool = false, diff --git a/bindings/napi/root.zig b/bindings/napi/root.zig index 13abd58f7..d48f59bc0 100644 --- a/bindings/napi/root.zig +++ b/bindings/napi/root.zig @@ -32,7 +32,7 @@ fn init(old_ref_count: u32) !void { } const n_workers = @min(cpu_count, @import("bls").ThreadPool.MAX_WORKERS); - try blst.initThreadPool(@intCast(n_workers)); + try blst.lifecycle.initThreadPool(@intCast(n_workers)); try pool.state.init(); try pubkeys.state.init(); config.state.init(); @@ -55,7 +55,7 @@ fn detectCpuCount() !usize { fn cleanup(new_ref_count: u32) void { if (new_ref_count == 0) { // Last environment — tear down shared state. - blst.deinitThreadPool(); + blst.lifecycle.deinitThreadPool(); config.state.deinit(); pubkeys.state.deinit(); pool.state.deinit(); diff --git a/build.zig.zon b/build.zig.zon index c1c37f6d4..326d2c865 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -40,8 +40,8 @@ .hash = "zig_yaml-0.1.0-C1161kFWAwDxjKAFmklKwWVDvz2mmq0Q__bDhGGjeyd3", }, .zapi = .{ - .url = "git+https://github.com/chainsafe/zapi.git?ref=zapi-v2.x.0#92fe4babe4022ceb94a5cb24022a18fe27417d69", - .hash = "zapi-2.2.0-rIqzUXBaBADUsvvvB2N5kOBdLEO0rGPhowTqmIXe3qVh", + .url = "https://github.com/ChainSafe/zapi/archive/refs/tags/zapi-v3.1.0.tar.gz", + .hash = "zapi-3.1.0-rIqzUQJsBADCFUrmxoTZyOhSTkcW6m3t_OgOHc6oxnm9", }, .zbench = .{ .url = "git+https://github.com/hendriknielaender/zBench#b2b89c475e3ef1bb2bd71255c80478a82d3e0ca8", diff --git a/package.json b/package.json index 28e4cd195..b198cba77 100644 --- a/package.json +++ b/package.json @@ -57,11 +57,8 @@ ] }, "dependencies": { - "@chainsafe/zapi": "github:ChainSafe/zapi#6649cef91b19bcd9854aa1ffa4d0c1aed7270f55" + "@chainsafe/zapi": "3.1.0" }, - "bundleDependencies": [ - "@chainsafe/zapi" - ], "devDependencies": { "@biomejs/biome": "^2.3.11", "@chainsafe/benchmark": "^2.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6611513b..b57408b12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@chainsafe/zapi': - specifier: github:ChainSafe/zapi#6649cef91b19bcd9854aa1ffa4d0c1aed7270f55 - version: https://codeload.github.com/ChainSafe/zapi/tar.gz/6649cef91b19bcd9854aa1ffa4d0c1aed7270f55 + specifier: 3.1.0 + version: 3.1.0 devDependencies: '@biomejs/biome': specifier: ^2.3.11 @@ -401,9 +401,8 @@ packages: resolution: {integrity: sha512-H8YdEoXXv2Hw17gDWGOJEya4LHlBbpChJP3jDQRfIk9hhwr0c/zbBemBRmjADowZhArL+ymkO+j5hGaYySjdpw==} engines: {node: '>= 18'} - '@chainsafe/zapi@https://codeload.github.com/ChainSafe/zapi/tar.gz/6649cef91b19bcd9854aa1ffa4d0c1aed7270f55': - resolution: {tarball: https://codeload.github.com/ChainSafe/zapi/tar.gz/6649cef91b19bcd9854aa1ffa4d0c1aed7270f55} - version: 2.2.0 + '@chainsafe/zapi@3.1.0': + resolution: {integrity: sha512-WRamllUXrrmx4G4qzmg0vRvcWQ+/Lgm7TgOFbqeJFPKlNv8CApTyA3BP6tudBaJyQYJSXlOn2RWrdv5e0EFwSw==} hasBin: true '@colors/colors@1.5.0': @@ -2443,7 +2442,7 @@ snapshots: '@chainsafe/swap-or-not-shuffle-win32-arm64-msvc': 1.2.1 '@chainsafe/swap-or-not-shuffle-win32-x64-msvc': 1.2.1 - '@chainsafe/zapi@https://codeload.github.com/ChainSafe/zapi/tar.gz/6649cef91b19bcd9854aa1ffa4d0c1aed7270f55': {} + '@chainsafe/zapi@3.1.0': {} '@colors/colors@1.5.0': optional: true