Skip to content

Commit b6d7f94

Browse files
committed
Merge branch 'main' into stf-slashings-penalties
2 parents e0d4509 + ce37c88 commit b6d7f94

90 files changed

Lines changed: 1706 additions & 404 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bench/state_transition/process_block.zig

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ const era = @import("era");
1515
const preset = state_transition.preset;
1616
const ForkSeq = config.ForkSeq;
1717
const CachedBeaconState = state_transition.CachedBeaconState;
18-
const ForkBeaconBlock = fork_types.ForkBeaconBlock;
19-
const ForkBeaconBlockBody = fork_types.ForkBeaconBlockBody;
18+
const BeaconBlock = fork_types.BeaconBlock;
19+
const BeaconBlockBody = fork_types.BeaconBlockBody;
2020
const ValidatorIndex = types.primitive.ValidatorIndex.Type;
2121
const PubkeyIndexMap = state_transition.PubkeyIndexMap(ValidatorIndex);
2222
const Withdrawals = types.capella.Withdrawals.Type;
@@ -33,7 +33,7 @@ const BenchOpts = struct {
3333
fn ProcessBlockHeaderBench(comptime fork: ForkSeq) type {
3434
return struct {
3535
cached_state: *CachedBeaconState,
36-
block: *const ForkBeaconBlock(fork, .full),
36+
block: *const BeaconBlock(.full, fork),
3737

3838
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
3939
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -56,7 +56,7 @@ fn ProcessBlockHeaderBench(comptime fork: ForkSeq) type {
5656
fn ProcessWithdrawalsBench(comptime fork: ForkSeq) type {
5757
return struct {
5858
cached_state: *CachedBeaconState,
59-
body: *const ForkBeaconBlockBody(fork, .full),
59+
body: *const BeaconBlockBody(.full, fork),
6060

6161
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
6262
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -101,7 +101,7 @@ fn ProcessWithdrawalsBench(comptime fork: ForkSeq) type {
101101
fn ProcessExecutionPayloadBench(comptime fork: ForkSeq) type {
102102
return struct {
103103
cached_state: *CachedBeaconState,
104-
body: *const ForkBeaconBlockBody(fork, .full),
104+
body: *const BeaconBlockBody(.full, fork),
105105

106106
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
107107
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -127,8 +127,8 @@ fn ProcessExecutionPayloadBench(comptime fork: ForkSeq) type {
127127
fn ProcessRandaoBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
128128
return struct {
129129
cached_state: *CachedBeaconState,
130-
block: *const ForkBeaconBlock(fork, .full),
131-
body: *const ForkBeaconBlockBody(fork, .full),
130+
block: *const BeaconBlock(.full, fork),
131+
body: *const BeaconBlockBody(.full, fork),
132132

133133
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
134134
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -153,7 +153,7 @@ fn ProcessRandaoBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
153153
fn ProcessEth1DataBench(comptime fork: ForkSeq) type {
154154
return struct {
155155
cached_state: *CachedBeaconState,
156-
body: *const ForkBeaconBlockBody(fork, .full),
156+
body: *const BeaconBlockBody(.full, fork),
157157

158158
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
159159
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -173,7 +173,7 @@ fn ProcessEth1DataBench(comptime fork: ForkSeq) type {
173173
fn ProcessOperationsBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
174174
return struct {
175175
cached_state: *CachedBeaconState,
176-
body: *const ForkBeaconBlockBody(fork, .full),
176+
body: *const BeaconBlockBody(.full, fork),
177177

178178
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
179179
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -198,7 +198,7 @@ fn ProcessOperationsBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type
198198
fn ProcessSyncAggregateBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
199199
return struct {
200200
cached_state: *CachedBeaconState,
201-
body: *const ForkBeaconBlockBody(fork, .full),
201+
body: *const BeaconBlockBody(.full, fork),
202202

203203
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
204204
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -222,7 +222,7 @@ fn ProcessSyncAggregateBench(comptime fork: ForkSeq, comptime opts: BenchOpts) t
222222
fn ProcessBlockBench(comptime fork: ForkSeq, comptime opts: BenchOpts) type {
223223
return struct {
224224
cached_state: *CachedBeaconState,
225-
block: *const ForkBeaconBlock(fork, .full),
225+
block: *const BeaconBlock(.full, fork),
226226

227227
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
228228
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -302,8 +302,8 @@ fn printSegmentStats(stdout: anytype) !void {
302302
fn ProcessBlockSegmentedBench(comptime fork: ForkSeq) type {
303303
return struct {
304304
cached_state: *CachedBeaconState,
305-
block: *const ForkBeaconBlock(fork, .full),
306-
body: *const ForkBeaconBlockBody(fork, .full),
305+
block: *const BeaconBlock(.full, fork),
306+
body: *const BeaconBlockBody(.full, fork),
307307

308308
pub fn run(self: @This(), allocator: std.mem.Allocator) void {
309309
const cloned = self.cached_state.clone(allocator, .{}) catch unreachable;
@@ -501,9 +501,7 @@ fn runBenchmark(comptime fork: ForkSeq, allocator: std.mem.Allocator, pool: *Nod
501501

502502
try state_transition.state_transition.processSlots(
503503
allocator,
504-
cached_state.config,
505-
cached_state.getEpochCache(),
506-
cached_state.state,
504+
cached_state,
507505
block_slot,
508506
.{},
509507
);

bench/state_transition/process_epoch.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ fn ProcessSlashingsBench(comptime fork: ForkSeq) type {
129129
cloned.getEpochCache(),
130130
cloned.state.castToFork(fork),
131131
&cache,
132-
false,
132+
true,
133133
) catch unreachable;
134134
}
135135
};

build.zig

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ pub fn build(b: *std.Build) void {
5656
.target = target,
5757
});
5858

59+
const dep_metrics = b.dependency("metrics", .{
60+
.optimize = optimize,
61+
.target = target,
62+
});
63+
64+
const dep_httpz = b.dependency("httpz", .{
65+
.optimize = optimize,
66+
.target = target,
67+
});
68+
5969
const module_constants = b.createModule(.{
6070
.root_source_file = b.path("src/constants/root.zig"),
6171
.target = target,
@@ -156,6 +166,29 @@ pub fn build(b: *std.Build) void {
156166
const tls_run_exe_download_era_files = b.step("run:download_era_files", "Run the download_era_files executable");
157167
tls_run_exe_download_era_files.dependOn(&run_exe_download_era_files.step);
158168

169+
const module_metrics_era = b.createModule(.{
170+
.root_source_file = b.path("examples/metrics_era.zig"),
171+
.target = target,
172+
.optimize = optimize,
173+
});
174+
b.modules.put(b.dupe("metrics_era"), module_metrics_era) catch @panic("OOM");
175+
176+
const exe_metrics_era = b.addExecutable(.{
177+
.name = "metrics_era",
178+
.root_module = module_metrics_era,
179+
});
180+
181+
const install_exe_metrics_era = b.addInstallArtifact(exe_metrics_era, .{});
182+
183+
const tls_install_exe_metrics_era = b.step("build-exe:metrics_era", "Install the metrics_era executable");
184+
tls_install_exe_metrics_era.dependOn(&install_exe_metrics_era.step);
185+
b.getInstallStep().dependOn(&install_exe_metrics_era.step);
186+
187+
const run_exe_metrics_era = b.addRunArtifact(exe_metrics_era);
188+
if (b.args) |args| run_exe_metrics_era.addArgs(args);
189+
const tls_run_exe_metrics_era = b.step("run:metrics_era", "Run the metrics_era executable");
190+
tls_run_exe_metrics_era.dependOn(&run_exe_metrics_era.step);
191+
159192
const module_download_spec_tests = b.createModule(.{
160193
.root_source_file = b.path("test/spec/download_spec_tests.zig"),
161194
.target = target,
@@ -604,6 +637,20 @@ pub fn build(b: *std.Build) void {
604637
tls_run_test_download_era_files.dependOn(&run_test_download_era_files.step);
605638
tls_run_test.dependOn(&run_test_download_era_files.step);
606639

640+
const test_metrics_era = b.addTest(.{
641+
.name = "metrics_era",
642+
.root_module = module_metrics_era,
643+
.filters = b.option([][]const u8, "metrics_era.filters", "metrics_era test filters") orelse &[_][]const u8{},
644+
});
645+
const install_test_metrics_era = b.addInstallArtifact(test_metrics_era, .{});
646+
const tls_install_test_metrics_era = b.step("build-test:metrics_era", "Install the metrics_era test");
647+
tls_install_test_metrics_era.dependOn(&install_test_metrics_era.step);
648+
649+
const run_test_metrics_era = b.addRunArtifact(test_metrics_era);
650+
const tls_run_test_metrics_era = b.step("test:metrics_era", "Run the metrics_era test");
651+
tls_run_test_metrics_era.dependOn(&run_test_metrics_era.step);
652+
tls_run_test.dependOn(&run_test_metrics_era.step);
653+
607654
const test_download_spec_tests = b.addTest(.{
608655
.name = "download_spec_tests",
609656
.root_module = module_download_spec_tests,
@@ -907,9 +954,18 @@ pub fn build(b: *std.Build) void {
907954
module_state_transition.addImport("constants", module_constants);
908955
module_state_transition.addImport("hex", module_hex);
909956
module_state_transition.addImport("persistent_merkle_tree", module_persistent_merkle_tree);
957+
module_state_transition.addImport("metrics", dep_metrics.module("metrics"));
910958

911959
module_download_era_files.addImport("download_era_options", options_module_download_era_options);
912960

961+
module_metrics_era.addImport("consensus_types", module_consensus_types);
962+
module_metrics_era.addImport("state_transition", module_state_transition);
963+
module_metrics_era.addImport("download_era_options", options_module_download_era_options);
964+
module_metrics_era.addImport("era", module_era);
965+
module_metrics_era.addImport("config", module_config);
966+
module_metrics_era.addImport("preset", module_preset);
967+
module_metrics_era.addImport("httpz", dep_httpz.module("httpz"));
968+
913969
module_download_spec_tests.addImport("spec_test_options", options_module_spec_test_options);
914970

915971
module_write_spec_tests.addImport("spec_test_options", options_module_spec_test_options);

build.zig.zon

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
.url = "git+https://github.com/hendriknielaender/zBench#d8c7dd485306b88b757d52005614ebcb0a336942",
2727
.hash = "zbench-0.10.0-YTdc714iAQDO4lTHMnIljYHPZ5v_sNTsw75vAmO1pyT-",
2828
},
29+
.metrics = .{
30+
.url = "git+https://github.com/karlseguin/metrics.zig.git#5f5420c98378a873a4bf816d69772c8f708a2273",
31+
.hash = "metrics-0.0.0-W7G4eHzVAQBMD2Iz5KUoKTssfqAloxCVd7xdG0gt1j5w",
32+
},
33+
.httpz = .{
34+
.url = "git+https://github.com/karlseguin/http.zig.git#2924ead41db9e1986db3b4909a82185c576f6361",
35+
.hash = "httpz-0.0.0-PNVzrC7CBgDSMZNP7chgAczR3FyAz5Eum6Kb1_K9kmYR",
36+
},
2937
},
3038
.paths = .{ "build.zig", "build.zig.zon", "src" },
3139
}

examples/metrics_era.zig

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//! Simple example to show collection of metrics using metrics.zig, with mainnet era files.
2+
//!
3+
//! Metrics are served on `port` on a separate thread, which is visualized through Prometheus,
4+
//! while we continuously run the state transition function using data from 2 consecutive era files.
5+
//! Run a Prometheus instance to see the data visually.
6+
//!
7+
//! To run this example, we first require era files: `zig build run:download_era_files`.
8+
//!
9+
//! Then, run `zig build run:metrics_era`.
10+
//!
11+
//! Note: this example is mainly meant to test that our metrics is working; realistically we do not need
12+
//! such an example. The bulk of this code should be moved to our beacon node implementation once it's ready.
13+
14+
const download_era_options = @import("download_era_options");
15+
const era = @import("era");
16+
const c = @import("config");
17+
const std = @import("std");
18+
const httpz = @import("httpz");
19+
const state_transition = @import("state_transition");
20+
const types = @import("consensus_types");
21+
22+
const CachedBeaconState = state_transition.CachedBeaconState;
23+
const SignedBlock = state_transition.SignedBlock;
24+
const active_preset = @import("preset").active_preset;
25+
const mainnet_chain_config = @import("config").mainnet.chain_config;
26+
const minimal_chain_config = @import("config").minimal.chain_config;
27+
const BeaconConfig = @import("config").BeaconConfig;
28+
const ValidatorIndex = @import("consensus_types").primitive.ValidatorIndex.Type;
29+
const Index2PubkeyCache = state_transition.Index2PubkeyCache;
30+
const PubkeyIndexMap = state_transition.PubkeyIndexMap(ValidatorIndex);
31+
const chain_config = if (active_preset == .mainnet) mainnet_chain_config else minimal_chain_config;
32+
33+
const MetricsHandler = struct {
34+
allocator: std.mem.Allocator,
35+
};
36+
37+
pub fn serveMetrics(
38+
allocator: std.mem.Allocator,
39+
port: u16,
40+
) !void {
41+
var handler = MetricsHandler{
42+
.allocator = allocator,
43+
};
44+
const address = "0.0.0.0";
45+
var server = try httpz.Server(*MetricsHandler).init(
46+
allocator,
47+
.{ .port = port, .address = address, .thread_pool = .{ .count = 1 } },
48+
&handler,
49+
);
50+
defer {
51+
server.stop();
52+
server.deinit();
53+
}
54+
var router = try server.router(.{});
55+
router.get("/metrics", getMetrics, .{});
56+
57+
std.log.info("Listening at {s}/{d}", .{ address, port });
58+
try server.listen(); // blocks
59+
}
60+
61+
/// Endpoint to write all state transition metrics to the server.
62+
fn getMetrics(_: *MetricsHandler, _: *httpz.Request, res: *httpz.Response) !void {
63+
res.content_type = .TEXT;
64+
const writer = res.writer();
65+
try state_transition.metrics.write(writer);
66+
}
67+
68+
fn eraReader(allocator: std.mem.Allocator, era_path: []const u8) !era.Reader {
69+
std.debug.print("Reading era file at {s}\n", .{era_path});
70+
return try era.Reader.open(allocator, c.mainnet.config, era_path);
71+
}
72+
73+
pub fn main() !void {
74+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
75+
const allocator = gpa.allocator();
76+
77+
_ = try std.Thread.spawn(.{}, serveMetrics, .{ allocator, 8008 });
78+
79+
try state_transition.metrics.init(allocator, .{});
80+
defer state_transition.metrics.state_transition.deinit();
81+
82+
const era_path_state = try std.fs.path.join(
83+
allocator,
84+
&[_][]const u8{ download_era_options.era_out_dir, download_era_options.era_files[0] },
85+
);
86+
defer allocator.free(era_path_state);
87+
const era_path_blocks = try std.fs.path.join(
88+
allocator,
89+
&[_][]const u8{ download_era_options.era_out_dir, download_era_options.era_files[1] },
90+
);
91+
defer allocator.free(era_path_blocks);
92+
93+
var reader_state = try eraReader(allocator, era_path_state);
94+
defer reader_state.close(allocator);
95+
var reader_blocks = try eraReader(allocator, era_path_blocks);
96+
defer reader_blocks.close(allocator);
97+
98+
std.debug.print("Reading state\n", .{});
99+
var state_ptr = try allocator.create(state_transition.BeaconState);
100+
errdefer allocator.destroy(state_ptr);
101+
state_ptr.* = try reader_state.readState(allocator, null);
102+
const blocks_index = reader_blocks.group_indices[0].blocks_index orelse return error.NoBlockIndex;
103+
const index_pubkey_cache = try allocator.create(Index2PubkeyCache);
104+
errdefer {
105+
index_pubkey_cache.deinit();
106+
allocator.destroy(index_pubkey_cache);
107+
}
108+
index_pubkey_cache.* = Index2PubkeyCache.init(allocator);
109+
const pubkey_index_map = try PubkeyIndexMap.init(allocator);
110+
errdefer pubkey_index_map.deinit();
111+
112+
const config = try allocator.create(BeaconConfig);
113+
errdefer allocator.destroy(config);
114+
config.* = BeaconConfig.init(chain_config, (try state_ptr.genesisValidatorsRoot()).*);
115+
116+
const immutable_data = state_transition.EpochCacheImmutableData{
117+
.config = config,
118+
.index_to_pubkey = index_pubkey_cache,
119+
.pubkey_to_index = pubkey_index_map,
120+
};
121+
122+
std.debug.print("Creating cached beacon state\n", .{});
123+
var cached_state = try CachedBeaconState.createCachedBeaconState(
124+
allocator,
125+
state_ptr,
126+
immutable_data,
127+
.{
128+
.skip_sync_committee_cache = state_ptr.forkSeq() == .phase0,
129+
.skip_sync_pubkeys = false,
130+
},
131+
);
132+
std.debug.print("Running state transition.\nYou may open up a local prometheus instance to check out metrics in action.\n", .{});
133+
for (blocks_index.start_slot + 1..blocks_index.start_slot + blocks_index.offsets.len) |slot| {
134+
const raw_block = try reader_blocks.readBlock(allocator, slot) orelse continue;
135+
defer raw_block.deinit(allocator);
136+
137+
const block: SignedBlock = .{ .regular = raw_block };
138+
139+
const block_num = switch (block.message().beaconBlockBody()) {
140+
.regular => |b| b.executionPayload().getBlockNumber(),
141+
.blinded => |b| b.executionPayloadHeader().getBlockNumber(),
142+
};
143+
std.debug.print("state slot = {}, block number = {}\n", .{ try cached_state.state.slot(), block_num });
144+
145+
const next = try state_transition.stateTransition(
146+
allocator,
147+
cached_state,
148+
block,
149+
.{
150+
.verify_signatures = false,
151+
.verify_proposer = false,
152+
.verify_state_root = false,
153+
},
154+
);
155+
156+
cached_state.deinit();
157+
allocator.destroy(cached_state);
158+
cached_state = next;
159+
}
160+
}

examples/prometheus.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copied from https://github.com/ChainSafe/lodestar/blob/unstable/prometheus.yml
2+
scrape_configs:
3+
- job_name: beacon
4+
scrape_interval: 5s
5+
metrics_path: /metrics
6+
static_configs:
7+
- targets: ["localhost:8008"]

0 commit comments

Comments
 (0)