Skip to content

Commit

Permalink
fix: make eventstream spec compliant
Browse files Browse the repository at this point in the history
  • Loading branch information
jeluard committed Jan 16, 2024
1 parent 4ff2911 commit 83218cb
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 43 deletions.
32 changes: 14 additions & 18 deletions packages/api/src/beacon/routes/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ export type EventData = {
executionOptimistic: boolean;
};
[EventType.contributionAndProof]: altair.SignedContributionAndProof;
[EventType.lightClientOptimisticUpdate]: allForks.LightClientOptimisticUpdate;
[EventType.lightClientFinalityUpdate]: allForks.LightClientFinalityUpdate;
[EventType.lightClientOptimisticUpdate]: {version: ForkName; data: allForks.LightClientOptimisticUpdate};
[EventType.lightClientFinalityUpdate]: {version: ForkName; data: allForks.LightClientFinalityUpdate};
[EventType.lightClientUpdate]: allForks.LightClientUpdate;
[EventType.payloadAttributes]: {version: ForkName; data: allForks.SSEPayloadAttributes};
[EventType.blobSidecar]: BlobSidecarSSE;
Expand Down Expand Up @@ -208,28 +208,24 @@ export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: Type
),
[EventType.blobSidecar]: blobSidecarSSE,

[EventType.lightClientOptimisticUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader((data as unknown as allForks.LightClientOptimisticUpdate).attestedHeader)[
[EventType.lightClientOptimisticUpdate]: WithVersion(
(_, data) => getLightClientTypeFromHeader((data as allForks.LightClientOptimisticUpdate).attestedHeader)[
"LightClientOptimisticUpdate"
].toJson(data),
fromJson: (data) =>
getLightClientTypeFromHeader(
],
(_, data) => getLightClientTypeFromHeader(
// eslint-disable-next-line @typescript-eslint/naming-convention
(data as {attested_header: allForks.LightClientHeader}).attested_header
)["LightClientOptimisticUpdate"].fromJson(data),
},
[EventType.lightClientFinalityUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader((data as unknown as allForks.LightClientFinalityUpdate).attestedHeader)[
)["LightClientOptimisticUpdate"]
),
[EventType.lightClientFinalityUpdate]: WithVersion(
(_, data) => getLightClientTypeFromHeader((data as unknown as allForks.LightClientFinalityUpdate).attestedHeader)[
"LightClientFinalityUpdate"
].toJson(data),
fromJson: (data) =>
getLightClientTypeFromHeader(
],
(_, data) => getLightClientTypeFromHeader(
// eslint-disable-next-line @typescript-eslint/naming-convention
(data as {attested_header: allForks.LightClientHeader}).attested_header
)["LightClientFinalityUpdate"].fromJson(data),
},
)["LightClientFinalityUpdate"]
),
[EventType.lightClientUpdate]: {
toJson: (data) =>
getLightClientTypeFromHeader((data as unknown as allForks.LightClientUpdate).attestedHeader)[
Expand Down
6 changes: 3 additions & 3 deletions packages/api/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ export function ContainerDataExecutionOptimistic<T>(
* version: ForkName
* ```
*/
export function WithVersion<T>(getType: (fork: ForkName) => TypeJson<T>): TypeJson<{data: T; version: ForkName}> {
export function WithVersion<T>(getTypeTo: (fork: ForkName, data: unknown) => TypeJson<T>, getTypeFrom: (fork: ForkName, data: unknown) => TypeJson<T> = getTypeTo): TypeJson<{data: T; version: ForkName}> {
return {
toJson: ({data, version}) => ({
data: getType(version ?? ForkName.phase0).toJson(data),
data: getTypeTo(version ?? ForkName.phase0, data).toJson(data),
version,
}),
fromJson: ({data, version}: {data: unknown; version: string}) => {
Expand All @@ -153,7 +153,7 @@ export function WithVersion<T>(getType: (fork: ForkName) => TypeJson<T>): TypeJs
if (!(version in ForkName)) throw Error(`Invalid version ${version}`);

return {
data: getType(version as ForkName).fromJson(data),
data: getTypeFrom(version as ForkName, data).fromJson(data),
version: version as ForkName,
};
},
Expand Down
56 changes: 48 additions & 8 deletions packages/api/test/unit/beacon/testData/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,56 @@ export const eventTestData: EventData = {
"0xac118511474a94f857300b315c50585c32a713e4452e26a6bb98cdb619936370f126ed3b6bb64469259ee92e69791d9e12d324ce6fd90081680ce72f39d85d50b0ff977260a8667465e613362c6d6e6e745e1f9323ec1d6f16041c4e358839ac",
}),
[EventType.lightClientOptimisticUpdate]: {
syncAggregate: ssz.altair.SyncAggregate.defaultValue(),
attestedHeader: ssz.altair.LightClientHeader.defaultValue(),
signatureSlot: ssz.Slot.defaultValue(),
version: ForkName.altair,
data: {
syncAggregate: ssz.altair.SyncAggregate.fromJson({
"sync_committee_bits": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
"sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
}),
attestedHeader: ssz.altair.LightClientHeader.fromJson({
"beacon": {
"body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"proposer_index": "1",
"slot": "1",
"state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
}
}),
signatureSlot: 1,
}
},
[EventType.lightClientFinalityUpdate]: {
attestedHeader: ssz.altair.LightClientHeader.defaultValue(),
finalizedHeader: ssz.altair.LightClientHeader.defaultValue(),
finalityBranch: [root],
syncAggregate: ssz.altair.SyncAggregate.defaultValue(),
signatureSlot: ssz.Slot.defaultValue(),
version: ForkName.altair,
data: {
attestedHeader: ssz.altair.LightClientHeader.fromJson({
"beacon": {
"slot": "1",
"proposer_index": "1",
"parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}
}),
finalizedHeader: ssz.altair.LightClientHeader.fromJson({
"beacon": {
"slot": "1",
"proposer_index": "1",
"parent_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"state_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"body_root": "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"}
}),
finalityBranch: ssz.altair.FinalityBranch.fromJson([
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
"0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2"]),
syncAggregate: ssz.altair.SyncAggregate.fromJson({
"sync_committee_bits": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
"sync_committee_signature": "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505"
}),
signatureSlot: 1,
}
},
[EventType.lightClientUpdate]: ssz.altair.LightClientUpdate.defaultValue(),
[EventType.payloadAttributes]: {
Expand Down
3 changes: 2 additions & 1 deletion packages/beacon-node/src/chain/blocks/importBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ export async function importBlock(
this.lightClientServer.onImportBlockHead(
block.message as allForks.AllForksLightClient["BeaconBlock"],
postState as CachedBeaconStateAltair,
parentBlockSlot
parentBlockSlot,
this.config.getForkName(block.message.slot)
);
} catch (e) {
this.logger.verbose("Error lightClientServer.onImportBlock", {slot: block.message.slot}, e as Error);
Expand Down
14 changes: 8 additions & 6 deletions packages/beacon-node/src/chain/lightClient/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ export class LightClientServer {
onImportBlockHead(
block: allForks.AllForksLightClient["BeaconBlock"],
postState: CachedBeaconStateAltair,
parentBlockSlot: Slot
parentBlockSlot: Slot,
fork: ForkName
): void {
// TEMP: To disable this functionality for fork_choice spec tests.
// Since the tests have deep-reorgs attested data is not available often printing lots of error logs.
Expand All @@ -247,7 +248,7 @@ export class LightClientServer {
const signedBlockRoot = block.parentRoot;
const syncPeriod = computeSyncPeriodAtSlot(block.slot);

this.onSyncAggregate(syncPeriod, block.body.syncAggregate, block.slot, signedBlockRoot).catch((e) => {
this.onSyncAggregate(syncPeriod, block.body.syncAggregate, block.slot, signedBlockRoot, fork).catch((e) => {
this.logger.error("Error onSyncAggregate", {}, e);
this.metrics?.lightclientServer.onSyncAggregate.inc({event: "error"});
});
Expand Down Expand Up @@ -455,7 +456,8 @@ export class LightClientServer {
syncPeriod: SyncPeriod,
syncAggregate: altair.SyncAggregate,
signatureSlot: Slot,
signedBlockRoot: Root
signedBlockRoot: Root,
fork: ForkName
): Promise<void> {
this.metrics?.lightclientServer.onSyncAggregate.inc({event: "processed"});

Expand Down Expand Up @@ -496,7 +498,7 @@ export class LightClientServer {

// Emit update
// Note: Always emit optimistic update even if we have emitted one with higher or equal attested_header.slot
this.emitter.emit(routes.events.EventType.lightClientOptimisticUpdate, headerUpdate);
this.emitter.emit(routes.events.EventType.lightClientOptimisticUpdate, {version: fork, data: headerUpdate});

// Persist latest best update for getLatestHeadUpdate()
// TODO: Once SyncAggregate are constructed from P2P too, count bits to decide "best"
Expand Down Expand Up @@ -529,8 +531,8 @@ export class LightClientServer {
};
this.metrics?.lightclientServer.onSyncAggregate.inc({event: "update_latest_finalized_update"});

// Note: Ignores gossip rule to always emit finaly_update with higher finalized_header.slot, for simplicity
this.emitter.emit(routes.events.EventType.lightClientFinalityUpdate, this.finalized);
// Note: Ignores gossip rule to always emit finality_update with higher finalized_header.slot, for simplicity
this.emitter.emit(routes.events.EventType.lightClientFinalityUpdate, {version: attestedFork, data: this.finalized});
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/network/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ export class Network implements INetwork {
this.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
this.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
this.chain.emitter.on(routes.events.EventType.head, this.onHead);
this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, this.onLightClientFinalityUpdate);
this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, this.onLightClientOptimisticUpdate);
this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, ({data}) => this.onLightClientFinalityUpdate(data));
this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, ({data}) => this.onLightClientOptimisticUpdate(data));
}

static async init({
Expand Down
4 changes: 2 additions & 2 deletions packages/light-client/src/transport/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ export class LightClientRestTransport extends (EventEmitter as {new (): RestEven
(event) => {
switch (event.type) {
case routes.events.EventType.lightClientOptimisticUpdate:
this.eventEmitter.emit(routes.events.EventType.lightClientOptimisticUpdate, event.message);
this.eventEmitter.emit(routes.events.EventType.lightClientOptimisticUpdate, event.message.data);
break;

case routes.events.EventType.lightClientFinalityUpdate:
this.eventEmitter.emit(routes.events.EventType.lightClientFinalityUpdate, event.message);
this.eventEmitter.emit(routes.events.EventType.lightClientFinalityUpdate, event.message.data);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/light-client/test/unit/sync.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ describe("sync", () => {
};

lightclientServerApi.latestHeadUpdate = headUpdate;
eventsServerApi.emit({type: routes.events.EventType.lightClientOptimisticUpdate, message: headUpdate});
eventsServerApi.emit({type: routes.events.EventType.lightClientOptimisticUpdate, message: {version: config.getForkName(slot), data: headUpdate}});
testLogger.debug("Emitted EventType.lightClientOptimisticUpdate", {slot});
}
});
Expand Down
6 changes: 4 additions & 2 deletions packages/types/src/altair/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,15 @@ export const LightClientBootstrap = new ContainerType(
{typeName: "LightClientBootstrap", jsonCase: "eth2"}
);

export const FinalityBranch = new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH);

export const LightClientUpdate = new ContainerType(
{
attestedHeader: LightClientHeader,
nextSyncCommittee: SyncCommittee,
nextSyncCommitteeBranch: new VectorCompositeType(Bytes32, NEXT_SYNC_COMMITTEE_DEPTH),
finalizedHeader: LightClientHeader,
finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH),
finalityBranch: FinalityBranch,
syncAggregate: SyncAggregate,
signatureSlot: Slot,
},
Expand All @@ -203,7 +205,7 @@ export const LightClientFinalityUpdate = new ContainerType(
{
attestedHeader: LightClientHeader,
finalizedHeader: LightClientHeader,
finalityBranch: new VectorCompositeType(Bytes32, FINALIZED_ROOT_DEPTH),
finalityBranch: FinalityBranch,
syncAggregate: SyncAggregate,
signatureSlot: Slot,
},
Expand Down

0 comments on commit 83218cb

Please sign in to comment.