Skip to content
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
541d640
chore: use tree view data pointers
wemeetagain Jan 8, 2026
0cdc10d
wip
wemeetagain Jan 8, 2026
587963b
fix: fix duplicate conflict syncCommitteeCache
GrapeBaBa Jan 9, 2026
e24495a
fix: fix missing pmt module in the state transition
GrapeBaBa Jan 9, 2026
adf0ccb
fix: add missing pool arg
GrapeBaBa Jan 9, 2026
3a36ba6
fix: fix generate_state test using treeview
GrapeBaBa Jan 9, 2026
60047f3
fix: fix seed isPostElectra migration
GrapeBaBa Jan 9, 2026
ba879cb
fix: fix beacon state get const ptr
GrapeBaBa Jan 9, 2026
ee58135
fix: fix generate_state test using setValue and getAllInto
GrapeBaBa Jan 9, 2026
9ddcb52
fix: fix fork epoch in the generate state
GrapeBaBa Jan 9, 2026
6807f23
fix: fix error union mismatch
GrapeBaBa Jan 9, 2026
2c10c6c
feat: add getAllReadonlyValues for array/list tree view
GrapeBaBa Jan 9, 2026
781d24f
fix: fix epoch cache get validators
GrapeBaBa Jan 9, 2026
2348644
fix: fix epoch cache issue
GrapeBaBa Jan 9, 2026
8ba1771
fix: fix several using tree view error
GrapeBaBa Jan 9, 2026
128b266
fix: processSlashings
wemeetagain Jan 9, 2026
76fa3c3
fix: processRewardsAndPenalties
wemeetagain Jan 9, 2026
5e8fcc6
fix: processRegistryUpdates
wemeetagain Jan 9, 2026
96bb17b
fix: processRandaoMixesReset
wemeetagain Jan 9, 2026
da46fde
fix: partially fix processProposerLookahead
wemeetagain Jan 9, 2026
cd5b954
fix: more processProposerLookahead
wemeetagain Jan 9, 2026
a0d7dd5
Merge remote-tracking branch 'origin/main' into tree-view-state
wemeetagain Jan 10, 2026
68a1b85
feat: add ListTreeView.iteratorReadonly
wemeetagain Jan 12, 2026
b019231
fix: processPendingDeposits
wemeetagain Jan 12, 2026
60fc413
fix: add electra/fulu in beacon execution payload
GrapeBaBa Jan 12, 2026
e2fb0aa
fix: fix beacon state test
GrapeBaBa Jan 12, 2026
524d58f
fix: fix state transition block
GrapeBaBa Jan 12, 2026
c4208b6
fix: fix state transition block issue
GrapeBaBa Jan 12, 2026
936ec93
fix: processPendingConsolidations
wemeetagain Jan 12, 2026
d1ad229
fix: processParticipationFlagUpdates
wemeetagain Jan 12, 2026
28b79ee
fix: processJustificationAndFinalization
wemeetagain Jan 12, 2026
0ac1ca0
fix: processInactivityUpdates
wemeetagain Jan 12, 2026
d353978
fix: processHistoricalSummariesUpdate
wemeetagain Jan 12, 2026
ad28b61
fix: processHistoricalRootsUpdate
wemeetagain Jan 12, 2026
02f2279
fix: processEth1DataReset
wemeetagain Jan 12, 2026
dfe5085
fix: processEffectiveBalanceUpdates
wemeetagain Jan 12, 2026
12602f5
fix: processEpoch
wemeetagain Jan 12, 2026
b59448f
feat: update TreeView.hashTreeRoot signature (return root const pointer)
wemeetagain Jan 12, 2026
27cefab
fix: stateTransition
wemeetagain Jan 12, 2026
619b003
fix: stray hashTreeRoot fixes
wemeetagain Jan 12, 2026
ddf127d
chore: remove interior mutability
wemeetagain Jan 12, 2026
7031c15
fix: start on sanity spec tests
wemeetagain Jan 12, 2026
22bf3c3
fix: fix state_transition test
GrapeBaBa Jan 13, 2026
fbd1dcf
fix: fix era treeview test
GrapeBaBa Jan 13, 2026
ef5c22f
fix: fix spec test unalign issue related to ownership
GrapeBaBa Jan 13, 2026
68d4a5f
fix: fix children nodes and datas cache not consistent
GrapeBaBa Jan 13, 2026
885f275
fix: fix skipped slots spec test
GrapeBaBa Jan 13, 2026
74c3e83
fix: remove debug log
GrapeBaBa Jan 13, 2026
b0ce31a
fix: various fixes
wemeetagain Jan 13, 2026
58f0cf8
fix: fix the phase0 epoch spec test
GrapeBaBa Jan 14, 2026
af8719b
fix: fix operation spec test
GrapeBaBa Jan 14, 2026
2b9582f
fix: fix finality spec test
GrapeBaBa Jan 14, 2026
5cce078
fix: fix random spec test
GrapeBaBa Jan 14, 2026
fe28bc6
fix: fix the phase0 fork spec test
GrapeBaBa Jan 14, 2026
f357119
fix: using setrootnode instead of transfer ownership
GrapeBaBa Jan 14, 2026
6f2294d
fix: fix altiar spec test
GrapeBaBa Jan 14, 2026
bd62993
fix: more spec test fixes
wemeetagain Jan 14, 2026
aad9fea
fix: simplify tree view semantics
wemeetagain Jan 14, 2026
c9527ae
fix: add TreeView.getReadonly behavior
wemeetagain Jan 14, 2026
03acfe3
fix: fixup becomesNewEth1Data
wemeetagain Jan 14, 2026
1b344f9
fix: bench_process_block
wemeetagain Jan 14, 2026
3a87de4
Merge branch 'main' into tree-view-state
GrapeBaBa Jan 15, 2026
e3303b4
fix: fix tests
GrapeBaBa Jan 15, 2026
caea327
refactor: make bench process epoch works
GrapeBaBa Jan 15, 2026
dbcd8c2
fix: fix lint
GrapeBaBa Jan 15, 2026
f034c58
fix: remove stray constCasts
wemeetagain Jan 15, 2026
ee69250
chore: use DebugAllocator in benchmarks
wemeetagain Jan 15, 2026
e1b9275
fix: illegal instruction
wemeetagain Jan 15, 2026
7464392
chore: minor tweaks
wemeetagain Jan 15, 2026
818e484
chore: commit state if verify_state_root = false
wemeetagain Jan 15, 2026
d273827
fix: slot check in processSlots
wemeetagain Jan 15, 2026
8f27a4c
chore: rename processSlots
wemeetagain Jan 15, 2026
9fb83a5
chore: fix bls wrapper test
wemeetagain Jan 15, 2026
5b1a961
chore: apply suggestions from code review
wemeetagain Jan 16, 2026
f7ee63b
fix: build errors
wemeetagain Jan 16, 2026
8990d8c
feat: rotateSyncCommittees
wemeetagain Jan 16, 2026
467e5ca
chore: more pr review
wemeetagain Jan 16, 2026
ad8b6ce
feat: add ssz.Type.default_root
wemeetagain Jan 9, 2026
bfd0c6a
feat: add ST.tree.default and ListST.tree.zeros
wemeetagain Jan 16, 2026
4e4dc56
chore: use EpochParticipation.tree.zeros to rotate epoch participation
wemeetagain Jan 16, 2026
7acc7d0
feat: BeaconState.balancesSlice
wemeetagain Jan 16, 2026
88d4f51
chore: remove allocator from processConsolidationRequest
wemeetagain Jan 16, 2026
30d8cca
chore: clean up processRandao
wemeetagain Jan 16, 2026
e66590c
chore: clean up BeaconState.populateFields
wemeetagain Jan 16, 2026
ac05476
chore: remove stale comment
wemeetagain Jan 16, 2026
12d3082
fix: errdefer remove dangling undefined in BaseTreeView.getChildDataR…
wemeetagain Jan 16, 2026
d10e670
chore: more comments on ListView.iteratorReadonly
wemeetagain Jan 16, 2026
0c70743
chore: use TreeView.getValue(out) pattern
wemeetagain Jan 16, 2026
be91097
chore: fix build errors
wemeetagain Jan 16, 2026
1fff4f1
fix: fix spec test failed
GrapeBaBa Jan 18, 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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ test/spec/test_case/
*.ssz
test/spec/ssz/generic_tests.zig
test/spec/ssz/static_tests.zig
*.era
*.era

# perf
flamegraph.html
perf.data
perf.data.old
107 changes: 66 additions & 41 deletions bench/state_transition/process_block.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@

const std = @import("std");
const zbench = @import("zbench");
const Node = @import("persistent_merkle_tree").Node;
const state_transition = @import("state_transition");
const types = @import("consensus_types");
const config = @import("config");
const download_era_options = @import("download_era_options");
const era = @import("era");
const preset = state_transition.preset;
const ForkSeq = config.ForkSeq;
const CachedBeaconStateAllForks = state_transition.CachedBeaconStateAllForks;
const BeaconStateAllForks = state_transition.BeaconStateAllForks;
const CachedBeaconState = state_transition.CachedBeaconState;
const BeaconState = state_transition.BeaconState;
const SignedBlock = state_transition.SignedBlock;
const SignedBeaconBlock = state_transition.SignedBeaconBlock;
const Body = state_transition.Body;
Expand All @@ -29,11 +32,11 @@ const BenchOpts = struct {
};

const ProcessBlockHeaderBench = struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: ProcessBlockHeaderBench, allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -44,11 +47,11 @@ const ProcessBlockHeaderBench = struct {
};

const ProcessWithdrawalsBench = struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: ProcessWithdrawalsBench, allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand Down Expand Up @@ -81,11 +84,11 @@ const ProcessWithdrawalsBench = struct {
};

const ProcessExecutionPayloadBench = struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
body: Body,

pub fn run(self: ProcessExecutionPayloadBench, allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -97,11 +100,11 @@ const ProcessExecutionPayloadBench = struct {

fn ProcessRandaoBench(comptime opts: BenchOpts) type {
return struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: @This(), allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -114,11 +117,11 @@ fn ProcessRandaoBench(comptime opts: BenchOpts) type {
}

const ProcessEth1DataBench = struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: ProcessEth1DataBench, allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -131,11 +134,11 @@ const ProcessEth1DataBench = struct {

fn ProcessOperationsBench(comptime opts: BenchOpts) type {
return struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: @This(), allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -149,11 +152,11 @@ fn ProcessOperationsBench(comptime opts: BenchOpts) type {

fn ProcessSyncAggregateBench(comptime opts: BenchOpts) type {
return struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: @This(), allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -167,11 +170,11 @@ fn ProcessSyncAggregateBench(comptime opts: BenchOpts) type {

fn ProcessBlockBench(comptime opts: BenchOpts) type {
return struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,

pub fn run(self: @This(), allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand Down Expand Up @@ -237,12 +240,12 @@ fn printSegmentStats(stdout: anytype) !void {
}

const ProcessBlockSegmentedBench = struct {
cached_state: *CachedBeaconStateAllForks,
cached_state: *CachedBeaconState,
signed_block: SignedBlock,
body: Body,

pub fn run(self: @This(), allocator: std.mem.Allocator) void {
const cloned = self.cached_state.clone(allocator) catch unreachable;
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
defer {
cloned.deinit();
allocator.destroy(cloned);
Expand All @@ -258,7 +261,7 @@ const ProcessBlockSegmentedBench = struct {
state_transition.processBlockHeader(allocator, cloned, block) catch unreachable;
recordSegment(.block_header, elapsedSince(header_start));

if (state.isPostCapella()) {
if (state.forkSeq().gte(.capella)) {
const withdrawals_start = std.time.nanoTimestamp();
var withdrawals_result = WithdrawalsResult{
.withdrawals = Withdrawals.initCapacity(allocator, preset.MAX_WITHDRAWALS_PER_PAYLOAD) catch unreachable,
Expand All @@ -280,7 +283,7 @@ const ProcessBlockSegmentedBench = struct {
recordSegment(.withdrawals, elapsedSince(withdrawals_start));
}

if (state.isPostBellatrix()) {
if (state.forkSeq().gte(.bellatrix)) {
const exec_start = std.time.nanoTimestamp();
const external_data = BlockExternalData{ .execution_payload_status = .valid, .data_availability_status = .available };
state_transition.processExecutionPayload(allocator, cloned, self.body, external_data) catch unreachable;
Expand All @@ -299,7 +302,7 @@ const ProcessBlockSegmentedBench = struct {
state_transition.processOperations(allocator, cloned, beacon_body, .{ .verify_signature = true }) catch unreachable;
recordSegment(.operations, elapsedSince(ops_start));

if (state.isPostAltair()) {
if (state.forkSeq().gte(.altair)) {
const sync_start = std.time.nanoTimestamp();
state_transition.processSyncAggregate(allocator, cloned, beacon_body.syncAggregate(), true) catch unreachable;
recordSegment(.sync_aggregate, elapsedSince(sync_start));
Expand All @@ -312,52 +315,74 @@ const ProcessBlockSegmentedBench = struct {
pub fn main() !void {
const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
var pool = try Node.Pool.init(allocator, 10_000_000);
defer pool.deinit();

const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const state_path = if (args.len > 1) args[1] else "bench/state_transition/state.ssz";
const block_path = if (args.len > 2) args[2] else "bench/state_transition/block.ssz";
// Use download_era_options.era_files[0] for state

const state_file = try std.fs.cwd().openFile(state_path, .{});
defer state_file.close();
const state_bytes = try state_file.readToEndAlloc(allocator, 10_000_000_000);
const era_path_0 = try std.fs.path.join(
allocator,
&[_][]const u8{ download_era_options.era_out_dir, download_era_options.era_files[0] },
);
defer allocator.free(era_path_0);

var era_reader_0 = try era.Reader.open(allocator, config.mainnet.config, era_path_0);
defer era_reader_0.close(allocator);

const state_bytes = try era_reader_0.readSerializedState(allocator, null);
defer allocator.free(state_bytes);

const chain_config = config.mainnet.chain_config;
const slot = slotFromStateBytes(state_bytes);
const detected_fork = config.mainnet.config.forkSeq(slot);
try stdout.print("Benchmarking processBlock with state at fork: {s} (slot {})\n", .{ @tagName(detected_fork), slot });

const block_file = try std.fs.cwd().openFile(block_path, .{});
defer block_file.close();
const block_bytes = try block_file.readToEndAlloc(allocator, 100_000_000);
// Use download_era_options.era_files[1] for state

const era_path_1 = try std.fs.path.join(
allocator,
&[_][]const u8{ download_era_options.era_out_dir, download_era_options.era_files[1] },
);
defer allocator.free(era_path_1);

var era_reader_1 = try era.Reader.open(allocator, config.mainnet.config, era_path_1);
defer era_reader_1.close(allocator);

const block_slot = try era.era.computeStartBlockSlotFromEraNumber(era_reader_1.era_number) + 1;

const block_bytes = try era_reader_1.readSerializedBlock(allocator, block_slot) orelse return error.InvalidEraFile;
defer allocator.free(block_bytes);

inline for (comptime std.enums.values(ForkSeq)) |fork| {
if (detected_fork == fork) return runBenchmark(fork, allocator, stdout, state_bytes, block_bytes, chain_config);
if (detected_fork == fork) return runBenchmark(fork, allocator, &pool, stdout, state_bytes, block_bytes, chain_config);
}
return error.NoBenchmarkRan;
}

fn runBenchmark(comptime fork: ForkSeq, allocator: std.mem.Allocator, stdout: anytype, state_bytes: []const u8, block_bytes: []const u8, chain_config: config.ChainConfig) !void {
const beacon_state = try loadState(fork, allocator, state_bytes);
fn runBenchmark(comptime fork: ForkSeq, allocator: std.mem.Allocator, pool: *Node.Pool, stdout: anytype, state_bytes: []const u8, block_bytes: []const u8, chain_config: config.ChainConfig) !void {
const beacon_state = try loadState(fork, allocator, pool, state_bytes);
const signed_beacon_block = try loadBlock(fork, allocator, block_bytes);
const block_slot = signed_beacon_block.beaconBlock().slot();
try stdout.print("Block: slot: {}\n", .{block_slot});

const beacon_config = config.BeaconConfig.init(chain_config, beacon_state.genesisValidatorsRoot());
const beacon_config = config.BeaconConfig.init(chain_config, (try beacon_state.genesisValidatorsRoot()).*);
const pubkey_index_map = try PubkeyIndexMap.init(allocator);
const index_pubkey_cache = try allocator.create(state_transition.Index2PubkeyCache);
index_pubkey_cache.* = state_transition.Index2PubkeyCache.init(allocator);
try state_transition.syncPubkeys(beacon_state.validators().items, pubkey_index_map, index_pubkey_cache);
const validators = try beacon_state.validatorsSlice(allocator);
defer allocator.free(validators);

try state_transition.syncPubkeys(validators, pubkey_index_map, index_pubkey_cache);

const cached_state = try CachedBeaconStateAllForks.createCachedBeaconState(allocator, beacon_state, .{
const cached_state = try CachedBeaconState.createCachedBeaconState(allocator, beacon_state, .{
.config = &beacon_config,
.index_to_pubkey = index_pubkey_cache,
.pubkey_to_index = pubkey_index_map,
}, .{ .skip_sync_committee_cache = !comptime fork.gte(.altair), .skip_sync_pubkeys = false });

try state_transition.state_transition.processSlotsWithTransientCache(allocator, cached_state, block_slot, .{});
try stdout.print("State: slot={}, validators={}\n", .{ cached_state.state.slot(), beacon_state.validators().items.len });
try cached_state.state.commit();
try stdout.print("State: slot={}, validators={}\n", .{ try cached_state.state.slot(), try beacon_state.validatorsCount() });

const signed_block = SignedBlock{ .regular = signed_beacon_block };
const body = Body{ .regular = signed_beacon_block.beaconBlock().beaconBlockBody() };
Expand Down Expand Up @@ -390,7 +415,7 @@ fn runBenchmark(comptime fork: ForkSeq, allocator: std.mem.Allocator, stdout: an
try bench.addParam("process_block", &ProcessBlockBench(.{ .verify_signature = true }){ .cached_state = cached_state, .signed_block = signed_block }, .{});
try bench.addParam("process_block_no_sig", &ProcessBlockBench(.{ .verify_signature = false }){ .cached_state = cached_state, .signed_block = signed_block }, .{});

// Segmented benchmark (step-by-step timing)
// // Segmented benchmark (step-by-step timing)
resetSegmentStats();
try bench.addParam("block(segments)", &ProcessBlockSegmentedBench{ .cached_state = cached_state, .signed_block = signed_block, .body = body }, .{});

Expand Down
Loading