Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9038c98
refactor: make XXXDecisionRoot fns return `js.String`
spiral-ladder May 1, 2026
a7c8844
update root related tests
spiral-ladder May 4, 2026
af2072e
fmt
spiral-ladder May 3, 2026
0b5c2a6
unabbreviate
spiral-ladder May 3, 2026
1bcb36f
refactor: make XXXDecisionRoot fns return `js.String`
spiral-ladder May 1, 2026
aa0369f
fix: param order in BeaconBlockBody
spiral-ladder May 1, 2026
ef383d9
refactor(bindings): return js.Number from getBalance
spiral-ladder May 1, 2026
7dc7a69
feat: align BeaconStateView to IBeaconStateView
spiral-ladder May 1, 2026
fd1c0a9
align doc comment for isExecutionEnabled
spiral-ladder May 5, 2026
58656ce
revert(bindings): pass SSZ bytes for voluntary exit validation
spiral-ladder May 5, 2026
0fe22ee
Fix getSingleProof param from any -> bigint
spiral-ladder May 5, 2026
aec1443
Merge branch 'main' into bing/native-stf
spiral-ladder May 5, 2026
45c2b20
revert slot value u32
spiral-ladder May 5, 2026
67084e3
revert: transitionOpts changes
spiral-ladder May 5, 2026
43b2244
fix doc comment for isExecutionEnabled
spiral-ladder May 5, 2026
0fe7152
doc: doc comment toValue stub
spiral-ladder May 5, 2026
b8e18e4
doc: doc comment CompactMultiProof type
spiral-ladder May 5, 2026
e2007c5
refactor: put `parseOptions` into `transition_opts.zig`
spiral-ladder May 5, 2026
37ca3b8
feat: naive loadOtherState
spiral-ladder May 5, 2026
342c1dc
fix rest of toU32 to toI64
spiral-ladder May 5, 2026
4909369
comments
spiral-ladder May 5, 2026
284e2bc
feat: bindings to `getExpectedWithdrawals` and native tweaks
spiral-ladder May 5, 2026
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
11 changes: 5 additions & 6 deletions bench/state_transition/process_block.zig
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,17 @@ fn ProcessWithdrawalsBench(comptime fork: ForkSeq) type {
allocator.destroy(cloned);
}

var withdrawals_buf: [preset.MAX_WITHDRAWALS_PER_PAYLOAD]types.capella.Withdrawal.Type = undefined;
var withdrawals_result = WithdrawalsResult{
.withdrawals = Withdrawals.initCapacity(allocator, preset.MAX_WITHDRAWALS_PER_PAYLOAD) catch unreachable,
.withdrawals = Withdrawals.initBuffer(&withdrawals_buf),
};
defer withdrawals_result.withdrawals.deinit(allocator);

var withdrawal_balances = std.AutoHashMap(ValidatorIndex, usize).init(allocator);
defer withdrawal_balances.deinit();

const state = cloned.state.castToFork(fork);
state_transition.getExpectedWithdrawals(
fork,
allocator,
cloned.epoch_cache,
state,
&withdrawals_result,
Expand Down Expand Up @@ -339,15 +338,15 @@ fn ProcessBlockSegmentedBench(comptime fork: ForkSeq) type {

if (comptime fork.gte(.capella)) {
const withdrawals_start = time.timestampNow(io);

var withdrawals_buf: [preset.MAX_WITHDRAWALS_PER_PAYLOAD]types.capella.Withdrawal.Type = undefined;
var withdrawals_result = WithdrawalsResult{
.withdrawals = Withdrawals.initCapacity(allocator, preset.MAX_WITHDRAWALS_PER_PAYLOAD) catch unreachable,
.withdrawals = Withdrawals.initBuffer(&withdrawals_buf),
};
defer withdrawals_result.withdrawals.deinit(allocator);
var withdrawal_balances = std.AutoHashMap(ValidatorIndex, usize).init(allocator);
defer withdrawal_balances.deinit();
state_transition.getExpectedWithdrawals(
fork,
allocator,
epoch_cache,
state,
&withdrawals_result,
Expand Down
547 changes: 473 additions & 74 deletions bindings/napi/BeaconStateView.zig

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions bindings/napi/js_types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ pub const Validator = js.Object(struct {
});

pub const ProposerRewards = js.Object(struct {
attestations: js.BigInt,
syncAggregate: js.BigInt,
slashing: js.BigInt,
attestations: js.Number,
syncAggregate: js.Number,
slashing: js.Number,
Comment on lines +59 to +61
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Reverting these fields to js.BigInt to avoid precision loss for u64 Gwei values, consistent with the feedback in BeaconStateView.zig.

    attestations: js.BigInt,
    syncAggregate: js.BigInt,
    slashing: js.BigInt,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We use number in IBeaconStateView instead of big ints

});

pub const MultiProof = js.Object(struct {
Expand Down
60 changes: 1 addition & 59 deletions bindings/napi/stateTransition.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,65 +15,7 @@ const allocator = if (builtin.mode == .Debug)
else
std.heap.c_allocator;

/// Parse a JS options object into Zig's TransitionOpts.
///
/// Recognized fields:
/// - verifyStateRoot, verifyProposer, verifySignatures: bool
/// - dontTransferCache: bool (negated to set transfer_cache)
/// - executionPayloadStatus: "valid" | "invalid" | "preMerge"
/// - dataAvailabilityStatus: "Available" | "PreData" | "OutOfRange"
///
/// This is the double negative version to conform with production lodestar.
/// TODO(bing): Eventually rename this to `transferCache` to avoid double negation because its confusing naming.
fn parseOptions(options: ?js.Value) !st.TransitionOpts {
var transition_opts: st.TransitionOpts = .{};
if (options) |value| {
const raw = value.toValue();
if (try raw.typeof() == .object) {
if (try raw.hasNamedProperty("verifyStateRoot")) {
transition_opts.verify_state_root = try (try raw.getNamedProperty("verifyStateRoot")).getValueBool();
}
if (try raw.hasNamedProperty("verifyProposer")) {
transition_opts.verify_proposer = try (try raw.getNamedProperty("verifyProposer")).getValueBool();
}
if (try raw.hasNamedProperty("verifySignatures")) {
transition_opts.verify_signatures = try (try raw.getNamedProperty("verifySignatures")).getValueBool();
}
if (try raw.hasNamedProperty("dontTransferCache")) {
transition_opts.transfer_cache = !(try (try raw.getNamedProperty("dontTransferCache")).getValueBool());
}
if (try raw.hasNamedProperty("executionPayloadStatus")) {
var buf: [16]u8 = undefined;
const execution_payload_status = try (try raw.getNamedProperty("executionPayloadStatus")).getValueStringUtf8(&buf);
transition_opts.block_external_data.execution_payload_status =
if (std.mem.eql(u8, execution_payload_status, "valid"))
.valid
else if (std.mem.eql(u8, execution_payload_status, "invalid"))
.invalid
else if (std.mem.eql(u8, execution_payload_status, "preMerge"))
.pre_merge
else
return error.InvalidExecutionPayloadStatus;
}
if (try raw.hasNamedProperty("dataAvailabilityStatus")) {
var buf: [16]u8 = undefined;
const da_status = try (try raw.getNamedProperty("dataAvailabilityStatus")).getValueStringUtf8(&buf);
transition_opts.block_external_data.data_availability_status =
if (std.mem.eql(u8, da_status, "Available"))
.available
else if (std.mem.eql(u8, da_status, "PreData"))
.pre_data
else if (std.mem.eql(u8, da_status, "OutOfRange"))
.out_of_range
// TODO(bing): uncomment once gloas support is in
// else if (std.mem.eql(u8, da_status, "NotRequired")) .not_required;
else
return error.InvalidDataAvailabilityStatus;
}
}
}
return transition_opts;
}
const parseOptions = @import("./transition_opts.zig").parseOptions;

/// Perform a state transition given a signed beacon block.
///
Expand Down
73 changes: 73 additions & 0 deletions bindings/napi/transition_opts.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//! Shared parser for `TransitionOpts` from a JS options object.
//!
//! This file is intentionally not registered with `root.zig` as a module export —
//! its `pub fn` should be visible to other napi files but never auto-exposed to JS.
//! (zapi tries to export every pub fn in modules listed in `root.zig`, which would
//! fail here because `TransitionOpts` isn't a JS-convertible return type.)

const std = @import("std");
const js = @import("zapi:zapi").js;
const st = @import("state_transition");

/// Parse a JS options object into Zig's `TransitionOpts`.
///
/// Recognized fields:
/// - `verifyStateRoot`, `verifyProposer`, `verifySignatures`: bool
/// - `dontTransferCache`: bool (negated to set `transfer_cache`)
/// - `executionPayloadStatus`: "valid" | "invalid" | "preMerge"
/// - `dataAvailabilityStatus`: "Available" | "PreData" | "OutOfRange"
///
/// Throws `error.InvalidExecutionPayloadStatus` / `error.InvalidDataAvailabilityStatus`
/// for unknown enum strings.
///
/// TODO(bing): rename `dontTransferCache` → `transferCache` to drop the double negation.
pub fn parseOptions(options: ?js.Value) !st.TransitionOpts {
var transition_opts: st.TransitionOpts = .{};

if (options) |value| {
const raw = value.toValue();
if (try raw.typeof() == .object) {
if (try raw.hasNamedProperty("verifyStateRoot")) {
transition_opts.verify_state_root = try (try raw.getNamedProperty("verifyStateRoot")).getValueBool();
}
if (try raw.hasNamedProperty("verifyProposer")) {
transition_opts.verify_proposer = try (try raw.getNamedProperty("verifyProposer")).getValueBool();
}
if (try raw.hasNamedProperty("verifySignatures")) {
transition_opts.verify_signatures = try (try raw.getNamedProperty("verifySignatures")).getValueBool();
}
if (try raw.hasNamedProperty("dontTransferCache")) {
transition_opts.transfer_cache = !(try (try raw.getNamedProperty("dontTransferCache")).getValueBool());
}
if (try raw.hasNamedProperty("executionPayloadStatus")) {
var buf: [16]u8 = undefined;
const status_str = try (try raw.getNamedProperty("executionPayloadStatus")).getValueStringUtf8(&buf);
transition_opts.block_external_data.execution_payload_status =
if (std.mem.eql(u8, status_str, "valid"))
.valid
else if (std.mem.eql(u8, status_str, "invalid"))
.invalid
else if (std.mem.eql(u8, status_str, "preMerge"))
.pre_merge
else
return error.InvalidExecutionPayloadStatus;
}
if (try raw.hasNamedProperty("dataAvailabilityStatus")) {
var buf: [16]u8 = undefined;
const da_str = try (try raw.getNamedProperty("dataAvailabilityStatus")).getValueStringUtf8(&buf);
transition_opts.block_external_data.data_availability_status =
if (std.mem.eql(u8, da_str, "Available"))
.available
else if (std.mem.eql(u8, da_str, "PreData"))
.pre_data
else if (std.mem.eql(u8, da_str, "OutOfRange"))
.out_of_range
// TODO(bing): uncomment once gloas support is in
// else if (std.mem.eql(u8, da_str, "NotRequired")) .not_required;
else
return error.InvalidDataAvailabilityStatus;
}
}
}
return transition_opts;
}
Loading
Loading