Skip to content

Commit 6b1f8ec

Browse files
committed
feat(network): harden peer discovery and sync transport
1 parent 02c9d46 commit 6b1f8ec

23 files changed

+2512
-299
lines changed

src/cli/commands/beacon/command.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ pub fn run(io: Io, allocator: Allocator, opts: anytype) !void {
242242
const enr_tcp6 = opts.@"enr.tcp6";
243243
const enr_udp6 = opts.@"enr.udp6";
244244
const target_peers = opts.targetPeers orelse opts.target_peers;
245+
const target_group_peers = opts.@"network.targetGroupPeers" orelse 6;
245246
const direct_peers_raw = opts.directPeers orelse opts.direct_peers;
246247
const checkpoint_state = opts.checkpointState orelse opts.checkpoint_state;
247248
const checkpoint_sync_url = opts.checkpointSyncUrl orelse opts.checkpoint_sync_url;
@@ -438,6 +439,7 @@ pub fn run(io: Io, allocator: Allocator, opts: anytype) !void {
438439
.builder_fault_inspection_window = builder_fault_window,
439440
.builder_allowed_faults = builder_allowed_faults,
440441
.target_peers = target_peers,
442+
.target_group_peers = target_group_peers,
441443
.network = network,
442444
.p2p_host = p2p_host4,
443445
.p2p_host6 = p2p_host6,

src/discv5/enr.zig

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ pub const Enr = struct {
5151
attnets: ?[8]u8,
5252
/// Sync committee subnet bitfield (1 byte = 4 sync committees)
5353
syncnets: ?[1]u8,
54+
/// PeerDAS custody group count (`cgc` ENR field).
55+
custody_group_count: ?u64,
5456
/// Raw RLP of the entire record (for signature verification and re-encoding)
5557
raw: []u8,
5658
alloc: Allocator,
@@ -110,6 +112,7 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!Enr {
110112
.eth2_raw = null,
111113
.attnets = null,
112114
.syncnets = null,
115+
.custody_group_count = null,
113116
.raw = try alloc.dupe(u8, data),
114117
.alloc = alloc,
115118
};
@@ -196,6 +199,13 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!Enr {
196199
if (val.len == 8) {
197200
enr.attnets = val[0..8].*;
198201
}
202+
} else if (std.mem.eql(u8, key, "cgc")) {
203+
const val = list.readBytes() catch return Error.InvalidEnr;
204+
if (val.len > 0 and val.len <= 8) {
205+
var count: u64 = 0;
206+
for (val) |b| count = (count << 8) | b;
207+
enr.custody_group_count = count;
208+
}
199209
} else if (std.mem.eql(u8, key, "syncnets")) {
200210
const val = list.readBytes() catch return Error.InvalidEnr;
201211
if (val.len == 1) {
@@ -259,6 +269,8 @@ pub const Builder = struct {
259269
eth2: ?[16]u8 = null,
260270
/// Attestation subnet bitfield (8 bytes = 64 bits for 64 subnets)
261271
attnets: ?[8]u8 = null,
272+
/// PeerDAS custody group count.
273+
custody_group_count: ?u64 = null,
262274
/// Sync committee subnet bitfield (1 byte = 4 bits for 4 sync committees)
263275
syncnets: ?[1]u8 = null,
264276

@@ -285,15 +297,28 @@ pub const Builder = struct {
285297
try writer.writeBytes(port_bytes[if (port_bytes[0] == 0) 1 else 0..2]);
286298
}
287299

300+
fn writeUint64Minimal(writer: *rlp.Writer, value: u64) !void {
301+
var bytes: [8]u8 = undefined;
302+
std.mem.writeInt(u64, &bytes, value, .big);
303+
304+
var start: usize = 0;
305+
while (start < bytes.len - 1 and bytes[start] == 0) : (start += 1) {}
306+
try writer.writeBytes(bytes[start..]);
307+
}
308+
288309
/// Write all key-value pairs in alphabetical order to an RLP writer.
289310
/// EIP-778 requires keys to be sorted.
290311
fn writeKVPairs(self: *const Builder, writer: *rlp.Writer, pubkey: *const [33]u8) !void {
291-
// Alphabetical order: attnets, eth2, id, ip, ip6, quic, quic6,
312+
// Alphabetical order: attnets, cgc, eth2, id, ip, ip6, quic, quic6,
292313
// secp256k1, syncnets, tcp, tcp6, udp, udp6
293314
if (self.attnets) |attnets| {
294315
try writer.writeBytes("attnets");
295316
try writer.writeBytes(&attnets);
296317
}
318+
if (self.custody_group_count) |count| {
319+
try writer.writeBytes("cgc");
320+
try writeUint64Minimal(writer, count);
321+
}
297322
if (self.eth2) |eth2_val| {
298323
try writer.writeBytes("eth2");
299324
try writer.writeBytes(&eth2_val);
@@ -474,6 +499,25 @@ test "ENR Builder: encode with eth2 and attnets" {
474499
try std.testing.expectEqual([8]u8{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, parsed.attnets.?);
475500
}
476501

502+
test "ENR Builder: encode with custody group count" {
503+
const hex_mod = @import("hex.zig");
504+
const alloc = std.testing.allocator;
505+
506+
const secret_key = hex_mod.hexToBytesComptime(32, "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291");
507+
var builder = Builder.init(alloc, secret_key, 1);
508+
builder.ip = [4]u8{ 127, 0, 0, 1 };
509+
builder.udp = 9000;
510+
builder.custody_group_count = 12;
511+
512+
const enr_bytes = try builder.encode();
513+
defer alloc.free(enr_bytes);
514+
515+
var parsed = try decode(alloc, enr_bytes);
516+
defer parsed.deinit();
517+
518+
try std.testing.expectEqual(@as(?u64, 12), parsed.custody_group_count);
519+
}
520+
477521
test "ENR Builder: encodeToString produces valid enr: prefix" {
478522
const hex_mod = @import("hex.zig");
479523
const alloc = std.testing.allocator;

src/discv5/service.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,7 @@ pub const Service = struct {
677677
builder.quic6 = parsed.quic6;
678678
builder.attnets = parsed.attnets;
679679
builder.syncnets = parsed.syncnets;
680+
builder.custody_group_count = parsed.custody_group_count;
680681
builder.eth2 = parsed.eth2_raw;
681682

682683
switch (addr) {

0 commit comments

Comments
 (0)