Skip to content

Commit 81aaeb5

Browse files
committed
feat: add and use metadatav3 for peer custody subnet
fixes for metadata, working locally change the condition to update metadata csc change
1 parent c7f6341 commit 81aaeb5

File tree

10 files changed

+96
-25
lines changed

10 files changed

+96
-25
lines changed

packages/beacon-node/src/network/metadata.ts

+21-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {BitArray} from "@chainsafe/ssz";
22
import {ForkSeq} from "@lodestar/params";
33
import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
4-
import {altair, Epoch, phase0, ssz} from "@lodestar/types";
4+
import {altair, Epoch, phase0, ssz, electra} from "@lodestar/types";
55
import {BeaconConfig} from "@lodestar/config";
66
import {FAR_FUTURE_EPOCH} from "../constants/index.js";
77
import {getCurrentAndNextFork} from "./forks.js";
@@ -19,7 +19,7 @@ export enum SubnetType {
1919
}
2020

2121
export type MetadataOpts = {
22-
metadata?: altair.Metadata;
22+
metadata?: electra.Metadata;
2323
};
2424

2525
export type MetadataModules = {
@@ -35,12 +35,15 @@ export type MetadataModules = {
3535
export class MetadataController {
3636
private onSetValue: (key: string, value: Uint8Array) => void;
3737
private config: BeaconConfig;
38-
private _metadata: altair.Metadata;
38+
private _metadata: electra.Metadata;
3939

4040
constructor(opts: MetadataOpts, modules: MetadataModules) {
4141
this.config = modules.config;
4242
this.onSetValue = modules.onSetValue;
43-
this._metadata = opts.metadata || ssz.altair.Metadata.defaultValue();
43+
this._metadata = opts.metadata ?? {
44+
...ssz.electra.Metadata.defaultValue(),
45+
csc: Math.max(this.config.CUSTODY_REQUIREMENT, this.config.NODE_CUSTODY_REQUIREMENT),
46+
};
4447
}
4548

4649
upstreamValues(currentEpoch: Epoch): void {
@@ -54,6 +57,10 @@ export class MetadataController {
5457
// adding syncnets to the ENR is not a problem, we will just have a useless field for a few hours.
5558
this.onSetValue(ENRKey.syncnets, ssz.phase0.AttestationSubnets.serialize(this._metadata.syncnets));
5659
}
60+
61+
if (this.config.getForkSeq(computeStartSlotAtEpoch(currentEpoch)) >= ForkSeq.electra) {
62+
this.onSetValue(ENRKey.csc, ssz.Uint8.serialize(this._metadata.csc));
63+
}
5764
}
5865

5966
get seqNumber(): bigint {
@@ -79,8 +86,17 @@ export class MetadataController {
7986
this._metadata.attnets = attnets;
8087
}
8188

89+
get csc(): number {
90+
return this._metadata.csc;
91+
}
92+
93+
set csc(csc: number) {
94+
this.onSetValue(ENRKey.csc, ssz.Uint8.serialize(csc));
95+
this._metadata.csc = csc;
96+
}
97+
8298
/** Consumers that need the phase0.Metadata type can just ignore the .syncnets property */
83-
get json(): altair.Metadata {
99+
get json(): electra.Metadata {
84100
return this._metadata;
85101
}
86102

packages/beacon-node/src/network/network.ts

+1
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ export class Network implements INetwork {
684684
};
685685

686686
private onPeerConnected = (data: NetworkEventData[NetworkEvent.peerConnected]): void => {
687+
this.logger.warn("onPeerConnected", {peer: data.peer, dataColumns: data.dataColumns.join(",")});
687688
this.connectedPeers.set(data.peer, data.dataColumns);
688689
};
689690

packages/beacon-node/src/network/peers/peerManager.ts

+25-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {Connection, PeerId} from "@libp2p/interface";
22
import {BitArray, toHexString} from "@chainsafe/ssz";
33
import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
44
import {BeaconConfig} from "@lodestar/config";
5-
import {Metadata, altair, phase0} from "@lodestar/types";
5+
import {Metadata, electra, phase0} from "@lodestar/types";
66
import {withTimeout} from "@lodestar/utils";
77
import {LoggerNode} from "@lodestar/logger/node";
88
import {GoodByeReasonCode, GOODBYE_KNOWN_CODES, Libp2pEvent} from "../../constants/index.js";
@@ -308,6 +308,11 @@ export class PeerManager {
308308
private onPing(peer: PeerId, seqNumber: phase0.Ping): void {
309309
// if the sequence number is unknown update the peer's metadata
310310
const metadata = this.connectedPeers.get(peer.toString())?.metadata;
311+
this.logger.warn("onPing", {
312+
seqNumber,
313+
metaSeqNumber: metadata?.seqNumber,
314+
cond: !metadata || metadata.seqNumber < seqNumber,
315+
});
311316
if (!metadata || metadata.seqNumber < seqNumber) {
312317
void this.requestMetadata(peer);
313318
}
@@ -320,12 +325,22 @@ export class PeerManager {
320325
// Store metadata always in case the peer updates attnets but not the sequence number
321326
// Trust that the peer always sends the latest metadata (From Lighthouse)
322327
const peerData = this.connectedPeers.get(peer.toString());
328+
this.logger.warn("onMetadata", {peer: peer.toString(), peerData: peerData !== undefined});
329+
console.log("onMetadata", metadata);
323330
if (peerData) {
331+
const oldMetadata = peerData.metadata;
324332
peerData.metadata = {
325333
seqNumber: metadata.seqNumber,
326334
attnets: metadata.attnets,
327-
syncnets: (metadata as Partial<altair.Metadata>).syncnets ?? BitArray.fromBitLen(SYNC_COMMITTEE_SUBNET_COUNT),
335+
syncnets: (metadata as Partial<electra.Metadata>).syncnets ?? BitArray.fromBitLen(SYNC_COMMITTEE_SUBNET_COUNT),
336+
csc:
337+
(metadata as Partial<electra.Metadata>).csc ??
338+
this.discovery?.["peerIdToCustodySubnetCount"].get(peer.toString()) ??
339+
this.config.CUSTODY_REQUIREMENT,
328340
};
341+
if (oldMetadata === null || oldMetadata.csc !== peerData.metadata.csc) {
342+
void this.requestStatus(peer, this.statusCache.get());
343+
}
329344
}
330345
}
331346

@@ -392,10 +407,10 @@ export class PeerManager {
392407
}
393408
if (getConnection(this.libp2p, peer.toString())) {
394409
const nodeId = peerData?.nodeId ?? computeNodeId(peer);
395-
const custodySubnetCount =
396-
peerData?.custodySubnetCount ?? this.discovery?.["peerIdToCustodySubnetCount"].get(peer.toString());
410+
console.log("onStatus", peerData?.metadata);
411+
const custodySubnetCount = peerData?.metadata?.csc;
397412

398-
const peerCustodySubnetCount = custodySubnetCount ?? this.config.CUSTODY_REQUIREMENT;
413+
const peerCustodySubnetCount = custodySubnetCount ?? 4;
399414
const peerCustodySubnets = getCustodyColumnSubnets(nodeId, peerCustodySubnetCount);
400415

401416
const matchingSubnetsNum = this.custodySubnets.reduce(
@@ -407,6 +422,7 @@ export class PeerManager {
407422

408423
this.logger.warn(`onStatus ${custodySubnetCount == undefined ? "undefined custody count assuming 4" : ""}`, {
409424
nodeId: toHexString(nodeId),
425+
myNodeId: toHexString(this.nodeId),
410426
peerId: peer.toString(),
411427
custodySubnetCount,
412428
hasAllColumns,
@@ -438,14 +454,17 @@ export class PeerManager {
438454

439455
private async requestMetadata(peer: PeerId): Promise<void> {
440456
try {
457+
this.logger.warn("requestMetadata", {peer: peer.toString()});
441458
this.onMetadata(peer, await this.reqResp.sendMetadata(peer));
442459
} catch (e) {
460+
console.log("requestMetadata", e);
443461
// TODO: Downvote peer here or in the reqResp layer
444462
}
445463
}
446464

447465
private async requestPing(peer: PeerId): Promise<void> {
448466
try {
467+
this.logger.warn("requestPing", {peer: peer.toString()});
449468
this.onPing(peer, await this.reqResp.sendPing(peer));
450469

451470
// If peer replies a PING request also update lastReceivedMsg
@@ -643,7 +662,6 @@ export class PeerManager {
643662
// If that happens, it's okay. Only the "outbound" connection triggers immediate action
644663
const now = Date.now();
645664
const nodeId = computeNodeId(remotePeer);
646-
const custodySubnetCount = this.discovery?.["peerIdToCustodySubnetCount"].get(remotePeer.toString()) ?? null;
647665
const peerData: PeerData = {
648666
lastReceivedMsgUnixTsMs: direction === "outbound" ? 0 : now,
649667
// If inbound, request after STATUS_INBOUND_GRACE_PERIOD
@@ -657,12 +675,11 @@ export class PeerManager {
657675
agentVersion: null,
658676
agentClient: null,
659677
encodingPreference: null,
660-
custodySubnetCount,
661678
};
662679
this.connectedPeers.set(remotePeer.toString(), peerData);
663680

664681
if (direction === "outbound") {
665-
//this.pingAndStatusTimeouts();
682+
// this.pingAndStatusTimeouts();
666683
void this.requestPing(remotePeer);
667684
void this.requestStatus(remotePeer, this.statusCache.get());
668685
}

packages/beacon-node/src/network/peers/peersData.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {PeerId} from "@libp2p/interface";
2-
import {altair} from "@lodestar/types";
2+
import {electra} from "@lodestar/types";
33
import {Encoding} from "@lodestar/reqresp";
44
import {NodeId} from "../subnets/interface.js";
55
import {ClientKind} from "./client.js";
@@ -20,11 +20,10 @@ export type PeerData = {
2020
direction: "inbound" | "outbound";
2121
peerId: PeerId;
2222
nodeId: NodeId | null;
23-
metadata: altair.Metadata | null;
23+
metadata: electra.Metadata | null;
2424
agentVersion: string | null;
2525
agentClient: ClientKind | null;
2626
encodingPreference: Encoding | null;
27-
custodySubnetCount: number | null;
2827
};
2928

3029
/**

packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,11 @@ export class ReqRespBeaconNode extends ReqResp {
192192
peerId,
193193
ReqRespMethod.Metadata,
194194
// Before altair, prioritize V2. After altair only request V2
195-
this.currentRegisteredFork >= ForkSeq.altair ? [Version.V2] : [(Version.V2, Version.V1)],
195+
this.currentRegisteredFork >= ForkSeq.electra
196+
? [Version.V3]
197+
: this.currentRegisteredFork >= ForkSeq.altair
198+
? [Version.V3, Version.V2]
199+
: [(Version.V3, Version.V2, Version.V1)],
196200
null
197201
),
198202
responseSszTypeByMethod[ReqRespMethod.Metadata]
@@ -257,6 +261,7 @@ export class ReqRespBeaconNode extends ReqResp {
257261

258262
if (ForkSeq[fork] >= ForkSeq.electra) {
259263
protocolsAtFork.push(
264+
[protocols.MetadataV3(this.config), this.onMetadata.bind(this)],
260265
[protocols.DataColumnSidecarsByRoot(this.config), this.getHandler(ReqRespMethod.DataColumnSidecarsByRoot)],
261266
[protocols.DataColumnSidecarsByRange(this.config), this.getHandler(ReqRespMethod.DataColumnSidecarsByRange)]
262267
);

packages/beacon-node/src/network/reqresp/protocols.ts

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export const MetadataV2 = toProtocol({
2323
contextBytesType: ContextBytesType.Empty,
2424
});
2525

26+
export const MetadataV3 = toProtocol({
27+
method: ReqRespMethod.Metadata,
28+
version: Version.V3,
29+
contextBytesType: ContextBytesType.Empty,
30+
});
31+
2632
export const Ping = toProtocol({
2733
method: ReqRespMethod.Ping,
2834
version: Version.V1,

packages/beacon-node/src/network/reqresp/types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ export const responseSszTypeByMethod: {[K in ReqRespMethod]: ResponseTypeGetter<
9797
[ReqRespMethod.Status]: () => ssz.phase0.Status,
9898
[ReqRespMethod.Goodbye]: () => ssz.phase0.Goodbye,
9999
[ReqRespMethod.Ping]: () => ssz.phase0.Ping,
100-
[ReqRespMethod.Metadata]: (_, version) => (version == Version.V1 ? ssz.phase0.Metadata : ssz.altair.Metadata),
100+
[ReqRespMethod.Metadata]: (_, version) =>
101+
version == Version.V1 ? ssz.phase0.Metadata : version == Version.V2 ? ssz.altair.Metadata : ssz.electra.Metadata,
101102
[ReqRespMethod.BeaconBlocksByRange]: blocksResponseType,
102103
[ReqRespMethod.BeaconBlocksByRoot]: blocksResponseType,
103104
[ReqRespMethod.BlobSidecarsByRange]: () => ssz.deneb.BlobSidecar,
@@ -126,6 +127,7 @@ export type RequestTypedContainer = {
126127
export enum Version {
127128
V1 = 1,
128129
V2 = 2,
130+
V3 = 3,
129131
}
130132

131133
export type OutgoingRequestArgs = {

packages/types/src/electra/sszTypes.ts

+23
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@ import {
1010

1111
import {ssz as primitiveSsz} from "../primitive/index.js";
1212
import {ssz as phase0Ssz} from "../phase0/index.js";
13+
import {ssz as altariSsz} from "../altair/index.js";
1314
import {ssz as denebSsz} from "../deneb/index.js";
1415

1516
const {BLSSignature, Root, ColumnIndex, Bytes32, Slot, UintNum64} = primitiveSsz;
1617

18+
export const Metadata = new ContainerType(
19+
{
20+
...altariSsz.Metadata.fields,
21+
csc: UintNum64,
22+
},
23+
{typeName: "Metadata", jsonCase: "eth2"}
24+
);
25+
1726
export const Cell = new ByteVectorType(BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_CELL);
1827
export const DataColumn = new ListCompositeType(Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK);
1928
export const ExtendedMatrix = new ListCompositeType(Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK * NUMBER_OF_COLUMNS);
@@ -200,3 +209,17 @@ export const SSEPayloadAttributes = new ContainerType(
200209
},
201210
{typeName: "SSEPayloadAttributes", jsonCase: "eth2"}
202211
);
212+
213+
export const BlockContents = new ContainerType(
214+
{
215+
...denebSsz.BlockContents.fields,
216+
},
217+
{typeName: "BlockContents", jsonCase: "eth2"}
218+
);
219+
220+
export const SignedBlockContents = new ContainerType(
221+
{
222+
...denebSsz.SignedBlockContents.fields,
223+
},
224+
{typeName: "SignedBlockContents", jsonCase: "eth2"}
225+
);

packages/types/src/electra/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {ValueOf} from "@chainsafe/ssz";
22
import * as ssz from "./sszTypes.js";
33

4+
export type Metadata = ValueOf<typeof ssz.Metadata>;
5+
46
export type Cell = ValueOf<typeof ssz.Cell>;
57
export type DataColumn = ValueOf<typeof ssz.DataColumn>;
68
export type ExtendedMatrix = ValueOf<typeof ssz.ExtendedMatrix>;
@@ -37,3 +39,7 @@ export type LightClientUpdate = ValueOf<typeof ssz.LightClientUpdate>;
3739
export type LightClientFinalityUpdate = ValueOf<typeof ssz.LightClientFinalityUpdate>;
3840
export type LightClientOptimisticUpdate = ValueOf<typeof ssz.LightClientOptimisticUpdate>;
3941
export type LightClientStore = ValueOf<typeof ssz.LightClientStore>;
42+
43+
export type BlockContents = ValueOf<typeof ssz.BlockContents>;
44+
export type SignedBlockContents = ValueOf<typeof ssz.SignedBlockContents>;
45+
export type Contents = Omit<BlockContents, "block">;

packages/types/src/types.ts

+3-7
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ type TypesByFork = {
141141
BeaconBlockBody: electra.BeaconBlockBody;
142142
BeaconState: electra.BeaconState;
143143
SignedBeaconBlock: electra.SignedBeaconBlock;
144-
Metadata: altair.Metadata;
144+
Metadata: electra.Metadata;
145145
LightClientHeader: electra.LightClientHeader;
146146
LightClientBootstrap: electra.LightClientBootstrap;
147147
LightClientUpdate: electra.LightClientUpdate;
@@ -156,12 +156,8 @@ type TypesByFork = {
156156
BuilderBid: electra.BuilderBid;
157157
SignedBuilderBid: electra.SignedBuilderBid;
158158
SSEPayloadAttributes: electra.SSEPayloadAttributes;
159-
BlockContents: {block: BeaconBlock<ForkName.electra>; kzgProofs: deneb.KZGProofs; blobs: deneb.Blobs};
160-
SignedBlockContents: {
161-
signedBlock: SignedBeaconBlock<ForkName.electra>;
162-
kzgProofs: deneb.KZGProofs;
163-
blobs: deneb.Blobs;
164-
};
159+
BlockContents: electra.BlockContents;
160+
SignedBlockContents: electra.SignedBlockContents;
165161
ExecutionPayloadAndBlobsBundle: deneb.ExecutionPayloadAndBlobsBundle;
166162
BlobsBundle: deneb.BlobsBundle;
167163
Contents: deneb.Contents;

0 commit comments

Comments
 (0)