From af46bab1b1ff383bafc36342bb5a03d8fdf2f447 Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 11:49:11 +0530 Subject: [PATCH 01/25] Add execution payload header to light client header capella onwards --- packages/params/src/index.ts | 11 +++++++++++ packages/types/src/allForks/sszTypes.ts | 15 +++++++++++++++ packages/types/src/allForks/types.ts | 13 +++++++++++++ packages/types/src/capella/sszTypes.ts | 19 +++++++++++++++++-- packages/types/src/capella/types.ts | 2 ++ packages/types/src/deneb/sszTypes.ts | 12 +++++++++++- 6 files changed, 69 insertions(+), 3 deletions(-) diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 4862d73ce280..2a8133f1fbee 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -186,6 +186,17 @@ export const FINALIZED_ROOT_GINDEX = 105; */ export const FINALIZED_ROOT_DEPTH = 6; export const FINALIZED_ROOT_INDEX = 41; + +// TODO: add correct values here +export const EXECUTION_PAYLOAD_GINDEX = 105; +/** + * ```ts + * Math.floor(Math.log2(EXECUTION_PAYLOAD_GINDEX)) + * ``` + */ +export const EXECUTION_PAYLOAD_DEPTH = 6; +export const EXECUTION_PAYLOAD_INDEX = 41; + /** * ```ts * config.types.altair.BeaconState.getPathGindex(["nextSyncCommittee"]) diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 37f755ff9eb0..195b3a7f266e 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -106,6 +106,21 @@ export const allForksBlinded = { }, }; +export const allForksLightClient = { + altair: { + LightClientHeader: altair.LightClientHeader, + }, + bellatrix: { + LightClientHeader: altair.LightClientHeader, + }, + capella: { + LightClientHeader: capella.LightClientHeader, + }, + eip4844: { + LightClientHeader: eip4844.LightClientHeader, + }, +}; + export const allForksBlobs = { deneb: { SignedBeaconBlockAndBlobsSidecar: deneb.SignedBeaconBlockAndBlobsSidecar, diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 0171a7254fd7..5bc3d9053b89 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -49,6 +49,8 @@ export type ExecutionPayloadHeader = | capella.ExecutionPayloadHeader | deneb.ExecutionPayloadHeader; +export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader; + // Blinded types that will change across forks export type BlindedBeaconBlockBody = | bellatrix.BlindedBeaconBlockBody @@ -83,6 +85,7 @@ export type AllForksTypes = { Metadata: Metadata; ExecutionPayload: ExecutionPayload; ExecutionPayloadHeader: ExecutionPayloadHeader; + LightClientHeader: LightClientHeader; BuilderBid: BuilderBid; SignedBuilderBid: SignedBuilderBid; SignedBeaconBlockAndBlobsSidecar: SignedBeaconBlockAndBlobsSidecar; @@ -94,6 +97,10 @@ export type AllForksBlindedTypes = { SignedBeaconBlock: SignedBlindedBeaconBlock; }; +export type AllForksLightClient = { + LightClientHeader: LightClientHeader; +}; + /** * An AllForks type must accept as any parameter the UNION of all fork types. * The generic argument of `AllForksTypeOf` must be the union of the fork types: @@ -200,6 +207,12 @@ export type AllForksBlindedSSZTypes = { >; }; +export type AllForksLightClientSSZTypes = { + BeaconBlockBody: AllForksTypeOf< + typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof eip4844Ssz.BeaconBlockBody + >; +}; + export type AllForksBlobsSSZTypes = { SignedBeaconBlockAndBlobsSidecar: AllForksTypeOf; }; diff --git a/packages/types/src/capella/sszTypes.ts b/packages/types/src/capella/sszTypes.ts index 3ad637455531..4df62d2725b6 100644 --- a/packages/types/src/capella/sszTypes.ts +++ b/packages/types/src/capella/sszTypes.ts @@ -1,5 +1,10 @@ -import {ContainerType, ListCompositeType} from "@chainsafe/ssz"; -import {HISTORICAL_ROOTS_LIMIT, MAX_WITHDRAWALS_PER_PAYLOAD, MAX_BLS_TO_EXECUTION_CHANGES} from "@lodestar/params"; +import {ContainerType, ListCompositeType, VectorCompositeType} from "@chainsafe/ssz"; +import { + HISTORICAL_ROOTS_LIMIT, + MAX_WITHDRAWALS_PER_PAYLOAD, + MAX_BLS_TO_EXECUTION_CHANGES, + EXECUTION_PAYLOAD_DEPTH, +} from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; @@ -16,6 +21,7 @@ const { ExecutionAddress, Gwei, UintBn256, + Bytes32, } = primitiveSsz; export const Withdrawal = new ContainerType( @@ -165,6 +171,15 @@ export const BeaconState = new ContainerType( {typeName: "BeaconState", jsonCase: "eth2"} ); +export const LightClientHeader = new ContainerType( + { + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); + export const BlindedBeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, diff --git a/packages/types/src/capella/types.ts b/packages/types/src/capella/types.ts index 2239a6d3537b..a09e86477cc7 100644 --- a/packages/types/src/capella/types.ts +++ b/packages/types/src/capella/types.ts @@ -14,6 +14,8 @@ export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; export type BeaconState = ValueOf; +export type LightClientHeader = ValueOf; + export type BlindedBeaconBlockBody = ValueOf; export type BlindedBeaconBlock = ValueOf; export type SignedBlindedBeaconBlock = ValueOf; diff --git a/packages/types/src/deneb/sszTypes.ts b/packages/types/src/deneb/sszTypes.ts index 9f79e2b23d74..9df0c8f06f1e 100644 --- a/packages/types/src/deneb/sszTypes.ts +++ b/packages/types/src/deneb/sszTypes.ts @@ -1,10 +1,11 @@ -import {ContainerType, ListCompositeType, ByteVectorType} from "@chainsafe/ssz"; +import {ContainerType, ListCompositeType, ByteVectorType, VectorCompositeType} from "@chainsafe/ssz"; import { HISTORICAL_ROOTS_LIMIT, FIELD_ELEMENTS_PER_BLOB, MAX_BLOBS_PER_BLOCK, MAX_REQUEST_BLOCKS, BYTES_PER_FIELD_ELEMENT, + EXECUTION_PAYLOAD_DEPTH, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -239,3 +240,12 @@ export const BeaconState = new ContainerType( }, {typeName: "BeaconState", jsonCase: "eth2"} ); + +export const LightClientHeader = new ContainerType( + { + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); From fc555a27a15d4a77e969defe01efae594dd81e0d Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 12:50:28 +0530 Subject: [PATCH 02/25] add more forks --- packages/params/src/forkName.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index ad19f63d5dc6..23fe84ea6473 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -20,12 +20,22 @@ export enum ForkSeq { deneb = 4, } -export type ForkExecution = Exclude; +export type ForkLightClient = Exclude; +export function isForkLightClient(fork: ForkName): fork is ForkLightClient { + return fork !== ForkName.phase0; +} + +export type ForkExecution = Exclude; export function isForkExecution(fork: ForkName): fork is ForkExecution { - return fork !== ForkName.phase0 && fork !== ForkName.altair; + return isForkLightClient(fork) && fork !== ForkName.altair; +} + +export type ForkWithdrawals = Exclude; +export function isForkWithdrawals(fork: ForkName): fork is ForkWithdrawals { + return isForkExecution(fork) && fork !== ForkName.capella; } export type ForkBlobs = Exclude; export function isForkBlobs(fork: ForkName): fork is ForkBlobs { - return isForkExecution(fork) && fork !== ForkName.bellatrix && fork !== ForkName.capella; + return isForkWithdrawals(fork) && fork !== ForkName.capella; } From 6f640814c4f75cbcb13f87e81488b68398c055d0 Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 13:01:26 +0530 Subject: [PATCH 03/25] add allfork types --- packages/config/src/forkConfig/index.ts | 17 ++++++++++++++++- packages/config/src/forkConfig/types.ts | 6 ++++-- packages/params/src/index.ts | 10 +++++++++- packages/types/src/allForks/types.ts | 4 +--- packages/types/src/sszTypes.ts | 1 + 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index cc82aab595c8..83a966422059 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -1,4 +1,12 @@ -import {GENESIS_EPOCH, ForkName, SLOTS_PER_EPOCH, ForkSeq, isForkExecution, isForkBlobs} from "@lodestar/params"; +import { + GENESIS_EPOCH, + ForkName, + SLOTS_PER_EPOCH, + ForkSeq, + isForkLightClient, + isForkExecution, + isForkBlobs, +} from "@lodestar/params"; import {Slot, allForks, Version, ssz} from "@lodestar/types"; import {IChainConfig} from "../chainConfig/index.js"; import {IForkConfig, IForkInfo} from "./types.js"; @@ -82,6 +90,13 @@ export function createIForkConfig(config: IChainConfig): IForkConfig { getForkTypes(slot: Slot): allForks.AllForksSSZTypes { return ssz.allForks[this.getForkName(slot)] as allForks.AllForksSSZTypes; }, + getLightClientForkTypes(slot: Slot): allForks.AllForksLightClientSSZTypes { + const forkName = this.getForkName(slot); + if (!isForkLightClient(forkName)) { + throw Error(`Invalid slot=${slot} fork=${forkName} for execution fork types`); + } + return ssz.allForksLightClient[forkName] as allForks.AllForksLightClientSSZTypes; + }, getExecutionForkTypes(slot: Slot): allForks.AllForksExecutionSSZTypes { const forkName = this.getForkName(slot); if (!isForkExecution(forkName)) { diff --git a/packages/config/src/forkConfig/types.ts b/packages/config/src/forkConfig/types.ts index 3404b07ca975..5619ee0b3cc3 100644 --- a/packages/config/src/forkConfig/types.ts +++ b/packages/config/src/forkConfig/types.ts @@ -30,10 +30,12 @@ export interface IForkConfig { getForkVersion(slot: Slot): Version; /** Get SSZ types by hard-fork */ getForkTypes(slot: Slot): allForks.AllForksSSZTypes; - /** Get execution SSZ tyoes by hard-fork*/ + /** Get lightclient SSZ types by hard-fork*/ + getLightClientForkTypes(slot: Slot): allForks.AllForksLightClientSSZTypes; + /** Get execution SSZ types by hard-fork*/ getExecutionForkTypes(slot: Slot): allForks.AllForksExecutionSSZTypes; /** Get blinded SSZ types by hard-fork */ getBlindedForkTypes(slot: Slot): allForks.AllForksBlindedSSZTypes; - /** Get blobs SSZ tyoes by hard-fork*/ + /** Get blobs SSZ types by hard-fork*/ getBlobsForkTypes(slot: Slot): allForks.AllForksBlobsSSZTypes; } diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 2a8133f1fbee..51b321cd839a 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -6,7 +6,15 @@ import {presetStatus} from "./presetStatus.js"; import {userSelectedPreset, userOverrides} from "./setPreset.js"; export {BeaconPreset} from "./interface.js"; -export {ForkName, ForkSeq, ForkExecution, ForkBlobs, isForkExecution, isForkBlobs} from "./forkName.js"; +export { + ForkName, + ForkSeq, + ForkExecution, + ForkBlobs, + isForkExecution, + isForkBlobs, + isForkLightClient, +} from "./forkName.js"; export {presetToJson} from "./json.js"; export {PresetName}; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 5bc3d9053b89..3db4569ca266 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -208,9 +208,7 @@ export type AllForksBlindedSSZTypes = { }; export type AllForksLightClientSSZTypes = { - BeaconBlockBody: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof eip4844Ssz.BeaconBlockBody - >; + LightClientHeader: AllForksTypeOf; }; export type AllForksBlobsSSZTypes = { diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 6a751fabfb6e..2a7df948a447 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -10,3 +10,4 @@ export const allForks = allForksSsz.allForks; export const allForksBlinded = allForksSsz.allForksBlinded; export const allForksExecution = allForksSsz.allForksExecution; export const allForksBlobs = allForksSsz.allForksBlobs; +export const allForksLightClient = allForksSsz.allForksLightClient; From 109d1e2a91c1bc9e11dd20ed66626c6ec0d50edc Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 16:55:26 +0530 Subject: [PATCH 04/25] make other types multifork --- .../db/repositories/lightclientBestUpdate.ts | 18 ++++- packages/beacon-node/src/util/multifork.ts | 22 ++++++ packages/config/src/forkConfig/index.ts | 14 ++-- packages/types/src/allForks/sszTypes.ts | 20 ++++++ packages/types/src/allForks/types.ts | 43 +++++++++++- packages/types/src/altair/types.ts | 2 + packages/types/src/capella/sszTypes.ts | 70 ++++++++++++++++--- packages/types/src/capella/types.ts | 9 ++- packages/types/src/deneb/sszTypes.ts | 52 ++++++++++++++ packages/types/src/deneb/types.ts | 7 ++ 10 files changed, 234 insertions(+), 23 deletions(-) diff --git a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts index b90e77dc1b44..552f52960408 100644 --- a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts +++ b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts @@ -1,14 +1,28 @@ import {IChainForkConfig} from "@lodestar/config"; import {Bucket, IDatabaseController, Repository} from "@lodestar/db"; -import {altair, ssz, SyncPeriod} from "@lodestar/types"; +import {ssz, SyncPeriod, allForks} from "@lodestar/types"; + +import {getLightClientUpdateTypeFromBytes} from "../../util/multifork.js"; /** * Best PartialLightClientUpdate in each SyncPeriod * * Used to prepare light client updates */ -export class BestLightClientUpdateRepository extends Repository { +export class BestLightClientUpdateRepository extends Repository { constructor(config: IChainForkConfig, db: IDatabaseController) { + // Pick some type but won't be used super(config, db, Bucket.lightClient_bestLightClientUpdate, ssz.altair.LightClientUpdate); } + + // Overrides for multi-fork + encodeValue(value: allForks.LightClientUpdate): Uint8Array { + return this.config + .getLightClientForkTypes(value.attestedHeader.beacon.slot) + .LightClientUpdate.serialize(value) as Uint8Array; + } + + decodeValue(data: Uint8Array): allForks.LightClientUpdate { + return getLightClientUpdateTypeFromBytes(this.config, data).deserialize(data); + } } diff --git a/packages/beacon-node/src/util/multifork.ts b/packages/beacon-node/src/util/multifork.ts index b131660382be..e72e4e28fcdc 100644 --- a/packages/beacon-node/src/util/multifork.ts +++ b/packages/beacon-node/src/util/multifork.ts @@ -53,3 +53,25 @@ export function getStateTypeFromBytes( const slot = bytesToInt(bytes.subarray(SLOT_BYTES_POSITION_IN_STATE, SLOT_BYTES_POSITION_IN_STATE + SLOT_BYTE_COUNT)); return config.getForkTypes(slot).BeaconState; } + +/** + * TODO: find correct position + * 8 + 32 = 40 + * ``` + * class BeaconState(Container): + * genesis_time: uint64 [fixed - 8 bytes] + * genesis_validators_root: Root [fixed - 32 bytes] + * slot: Slot [fixed - 8 bytes] + * ... + * ``` + */ +const SLOT_BYTES_POSITION_IN_LIGHTCLIENTUPDATE = 40; +export function getLightClientUpdateTypeFromBytes( + config: IChainForkConfig, + bytes: Buffer | Uint8Array +): allForks.AllForksLightClientSSZTypes["LightClientUpdate"] { + const slot = bytesToInt( + bytes.subarray(SLOT_BYTES_POSITION_IN_LIGHTCLIENTUPDATE, SLOT_BYTES_POSITION_IN_LIGHTCLIENTUPDATE + SLOT_BYTE_COUNT) + ); + return config.getLightClientForkTypes(slot).LightClientUpdate; +} diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 83a966422059..3937a0fc71d9 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -90,13 +90,6 @@ export function createIForkConfig(config: IChainConfig): IForkConfig { getForkTypes(slot: Slot): allForks.AllForksSSZTypes { return ssz.allForks[this.getForkName(slot)] as allForks.AllForksSSZTypes; }, - getLightClientForkTypes(slot: Slot): allForks.AllForksLightClientSSZTypes { - const forkName = this.getForkName(slot); - if (!isForkLightClient(forkName)) { - throw Error(`Invalid slot=${slot} fork=${forkName} for execution fork types`); - } - return ssz.allForksLightClient[forkName] as allForks.AllForksLightClientSSZTypes; - }, getExecutionForkTypes(slot: Slot): allForks.AllForksExecutionSSZTypes { const forkName = this.getForkName(slot); if (!isForkExecution(forkName)) { @@ -111,6 +104,13 @@ export function createIForkConfig(config: IChainConfig): IForkConfig { } return ssz.allForksBlinded[forkName] as allForks.AllForksBlindedSSZTypes; }, + getLightClientForkTypes(slot: Slot): allForks.AllForksLightClientSSZTypes { + const forkName = this.getForkName(slot); + if (!isForkLightClient(forkName)) { + throw Error(`Invalid slot=${slot} fork=${forkName} for execution fork types`); + } + return ssz.allForksLightClient[forkName] as allForks.AllForksLightClientSSZTypes; + }, getBlobsForkTypes(slot: Slot): allForks.AllForksBlobsSSZTypes { const forkName = this.getForkName(slot); if (!isForkBlobs(forkName)) { diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 195b3a7f266e..4ec3b4271f18 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -109,15 +109,35 @@ export const allForksBlinded = { export const allForksLightClient = { altair: { LightClientHeader: altair.LightClientHeader, + LightClientBootstrap: altair.LightClientBootstrap, + LightClientUpdate: altair.LightClientUpdate, + LightClientFinalityUpdate: altair.LightClientFinalityUpdate, + LightClientOptimisticUpdate: altair.LightClientOptimisticUpdate, + LightClientStore: altair.LightClientStore, }, bellatrix: { LightClientHeader: altair.LightClientHeader, + LightClientBootstrap: altair.LightClientBootstrap, + LightClientUpdate: altair.LightClientUpdate, + LightClientFinalityUpdate: altair.LightClientFinalityUpdate, + LightClientOptimisticUpdate: altair.LightClientOptimisticUpdate, + LightClientStore: altair.LightClientStore, }, capella: { LightClientHeader: capella.LightClientHeader, + LightClientBootstrap: capella.LightClientBootstrap, + LightClientUpdate: capella.LightClientUpdate, + LightClientFinalityUpdate: capella.LightClientFinalityUpdate, + LightClientOptimisticUpdate: capella.LightClientOptimisticUpdate, + LightClientStore: capella.LightClientStore, }, eip4844: { LightClientHeader: eip4844.LightClientHeader, + LightClientBootstrap: eip4844.LightClientBootstrap, + LightClientUpdate: eip4844.LightClientUpdate, + LightClientFinalityUpdate: eip4844.LightClientFinalityUpdate, + LightClientOptimisticUpdate: eip4844.LightClientOptimisticUpdate, + LightClientStore: eip4844.LightClientStore, }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 3db4569ca266..b858f5ee75dc 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -49,8 +49,6 @@ export type ExecutionPayloadHeader = | capella.ExecutionPayloadHeader | deneb.ExecutionPayloadHeader; -export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader; - // Blinded types that will change across forks export type BlindedBeaconBlockBody = | bellatrix.BlindedBeaconBlockBody @@ -73,6 +71,22 @@ export type FullOrBlindedSignedBeaconBlock = SignedBeaconBlock | SignedBlindedBe export type BuilderBid = bellatrix.BuilderBid | capella.BuilderBid | deneb.BuilderBid; export type SignedBuilderBid = bellatrix.SignedBuilderBid | capella.SignedBuilderBid | deneb.SignedBuilderBid; +export type LightClientHeader = altair.LightClientHeader | capella.LightClientHeader | deneb.LightClientHeader; +export type LightClientBootstrap = + | altair.LightClientBootstrap + | capella.LightClientBootstrap + | deneb.LightClientBootstrap; +export type LightClientUpdate = altair.LightClientUpdate | capella.LightClientUpdate | deneb.LightClientUpdate; +export type LightClientFinalityUpdate = + | altair.LightClientFinalityUpdate + | capella.LightClientFinalityUpdate + | deneb.LightClientFinalityUpdate; +export type LightClientOptimisticUpdate = + | altair.LightClientOptimisticUpdate + | capella.LightClientOptimisticUpdate + | deneb.LightClientOptimisticUpdate; +export type LightClientStore = altair.LightClientStore | capella.LightClientStore | deneb.LightClientStore; + export type SignedBeaconBlockAndBlobsSidecar = deneb.SignedBeaconBlockAndBlobsSidecar; /** * Types known to change between forks @@ -208,7 +222,30 @@ export type AllForksBlindedSSZTypes = { }; export type AllForksLightClientSSZTypes = { - LightClientHeader: AllForksTypeOf; + LightClientHeader: AllForksTypeOf< + typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader + >; + LightClientBootstrap: AllForksTypeOf< + | typeof altairSsz.LightClientBootstrap + | typeof capellaSsz.LightClientBootstrap + | typeof denebSsz.LightClientBootstrap + >; + LightClientUpdate: AllForksTypeOf< + typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate + >; + LightClientFinalityUpdate: AllForksTypeOf< + | typeof altairSsz.LightClientFinalityUpdate + | typeof capellaSsz.LightClientFinalityUpdate + | typeof denebSsz.LightClientFinalityUpdate + >; + LightClientOptimisticUpdate: AllForksTypeOf< + | typeof altairSsz.LightClientOptimisticUpdate + | typeof capellaSsz.LightClientOptimisticUpdate + | typeof denebSsz.LightClientOptimisticUpdate + >; + LightClientStore: AllForksTypeOf< + typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore + >; }; export type AllForksBlobsSSZTypes = { diff --git a/packages/types/src/altair/types.ts b/packages/types/src/altair/types.ts index a805144e1def..f891bcca376f 100644 --- a/packages/types/src/altair/types.ts +++ b/packages/types/src/altair/types.ts @@ -14,9 +14,11 @@ export type BeaconBlockBody = ValueOf; export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; export type BeaconState = ValueOf; + export type LightClientHeader = ValueOf; export type LightClientBootstrap = ValueOf; export type LightClientUpdate = ValueOf; export type LightClientFinalityUpdate = ValueOf; export type LightClientOptimisticUpdate = ValueOf; +export type LightClientStore = ValueOf; export type LightClientUpdatesByRange = ValueOf; diff --git a/packages/types/src/capella/sszTypes.ts b/packages/types/src/capella/sszTypes.ts index 4df62d2725b6..734032f9f88c 100644 --- a/packages/types/src/capella/sszTypes.ts +++ b/packages/types/src/capella/sszTypes.ts @@ -4,6 +4,8 @@ import { MAX_WITHDRAWALS_PER_PAYLOAD, MAX_BLS_TO_EXECUTION_CHANGES, EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -171,15 +173,6 @@ export const BeaconState = new ContainerType( {typeName: "BeaconState", jsonCase: "eth2"} ); -export const LightClientHeader = new ContainerType( - { - beacon: phase0Ssz.BeaconBlockHeader, - execution: ExecutionPayloadHeader, - executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), - }, - {typeName: "LightClientHeader", jsonCase: "eth2"} -); - export const BlindedBeaconBlockBody = new ContainerType( { ...altairSsz.BeaconBlockBody.fields, @@ -208,3 +201,62 @@ export const SignedBlindedBeaconBlock = new ContainerType( }, {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} ); + +export const LightClientHeader = new ContainerType( + { + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); + +export const LightClientBootstrap = new ContainerType( + { + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, + }, + {typeName: "LightClientBootstrap", jsonCase: "eth2"} +); + +export const LightClientUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientUpdate", jsonCase: "eth2"} +); + +export const LightClientFinalityUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} +); + +export const LightClientOptimisticUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} +); + +export const LightClientStore = new ContainerType( + { + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), + }, + {typeName: "LightClientStore", jsonCase: "eth2"} +); diff --git a/packages/types/src/capella/types.ts b/packages/types/src/capella/types.ts index a09e86477cc7..1dfb375fb358 100644 --- a/packages/types/src/capella/types.ts +++ b/packages/types/src/capella/types.ts @@ -14,8 +14,6 @@ export type BeaconBlock = ValueOf; export type SignedBeaconBlock = ValueOf; export type BeaconState = ValueOf; -export type LightClientHeader = ValueOf; - export type BlindedBeaconBlockBody = ValueOf; export type BlindedBeaconBlock = ValueOf; export type SignedBlindedBeaconBlock = ValueOf; @@ -24,3 +22,10 @@ export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadH export type BuilderBid = ValueOf; export type SignedBuilderBid = ValueOf; + +export type LightClientHeader = ValueOf; +export type LightClientBootstrap = ValueOf; +export type LightClientUpdate = ValueOf; +export type LightClientFinalityUpdate = ValueOf; +export type LightClientOptimisticUpdate = ValueOf; +export type LightClientStore = ValueOf; diff --git a/packages/types/src/deneb/sszTypes.ts b/packages/types/src/deneb/sszTypes.ts index 9df0c8f06f1e..f7aff6efaf53 100644 --- a/packages/types/src/deneb/sszTypes.ts +++ b/packages/types/src/deneb/sszTypes.ts @@ -6,6 +6,8 @@ import { MAX_REQUEST_BLOCKS, BYTES_PER_FIELD_ELEMENT, EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, } from "@lodestar/params"; import {ssz as primitiveSsz} from "../primitive/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; @@ -249,3 +251,53 @@ export const LightClientHeader = new ContainerType( }, {typeName: "LightClientHeader", jsonCase: "eth2"} ); + +export const LightClientBootstrap = new ContainerType( + { + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, + }, + {typeName: "LightClientBootstrap", jsonCase: "eth2"} +); + +export const LightClientUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientUpdate", jsonCase: "eth2"} +); + +export const LightClientFinalityUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} +); + +export const LightClientOptimisticUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} +); + +export const LightClientStore = new ContainerType( + { + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), + }, + {typeName: "LightClientStore", jsonCase: "eth2"} +); diff --git a/packages/types/src/deneb/types.ts b/packages/types/src/deneb/types.ts index b185d1afad0c..bb419bd3d00a 100644 --- a/packages/types/src/deneb/types.ts +++ b/packages/types/src/deneb/types.ts @@ -32,3 +32,10 @@ export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadH export type BuilderBid = ValueOf; export type SignedBuilderBid = ValueOf; + +export type LightClientHeader = ValueOf; +export type LightClientBootstrap = ValueOf; +export type LightClientUpdate = ValueOf; +export type LightClientFinalityUpdate = ValueOf; +export type LightClientOptimisticUpdate = ValueOf; +export type LightClientStore = ValueOf; From 7e54f664aeec70d968051bced0207dfe862deab9 Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 18:10:29 +0530 Subject: [PATCH 05/25] make events multifork compatible --- packages/api/src/beacon/client/events.ts | 4 +-- packages/api/src/beacon/routes/events.ts | 37 ++++++++++++++---------- packages/api/src/beacon/server/events.ts | 2 +- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/api/src/beacon/client/events.ts b/packages/api/src/beacon/client/events.ts index 996899f98a1f..208cd44d7514 100644 --- a/packages/api/src/beacon/client/events.ts +++ b/packages/api/src/beacon/client/events.ts @@ -7,8 +7,8 @@ import {HttpStatusCode} from "../../utils/client/httpStatusCode.js"; /** * REST HTTP client for events routes */ -export function getClient(_config: IChainForkConfig, baseUrl: string): Api { - const eventSerdes = getEventSerdes(); +export function getClient(config: IChainForkConfig, baseUrl: string): Api { + const eventSerdes = getEventSerdes(config); return { eventstream: async (topics, signal, onEvent) => { diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 1b139cc39cf3..a7ed174c5479 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -1,6 +1,8 @@ -import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64} from "@lodestar/types"; -import {ContainerType, Type, VectorCompositeType} from "@chainsafe/ssz"; +import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64, allForks} from "@lodestar/types"; +import {ContainerType, VectorCompositeType} from "@chainsafe/ssz"; import {FINALIZED_ROOT_DEPTH} from "@lodestar/params"; +import {IChainForkConfig} from "@lodestar/config"; + import {RouteDef, TypeJson} from "../../utils/index.js"; import {HttpStatusCode} from "../../utils/client/httpStatusCode.js"; import {ApiClientResponse} from "../../interfaces.js"; @@ -86,9 +88,9 @@ export type EventData = { executionOptimistic: boolean; }; [EventType.contributionAndProof]: altair.SignedContributionAndProof; - [EventType.lightClientOptimisticUpdate]: altair.LightClientOptimisticUpdate; - [EventType.lightClientFinalityUpdate]: altair.LightClientFinalityUpdate; - [EventType.lightClientUpdate]: altair.LightClientUpdate; + [EventType.lightClientOptimisticUpdate]: allForks.LightClientOptimisticUpdate; + [EventType.lightClientFinalityUpdate]: allForks.LightClientFinalityUpdate; + [EventType.lightClientUpdate]: allForks.LightClientUpdate; }; export type BeaconEvent = {[K in EventType]: {type: K; message: EventData[K]}}[EventType]; @@ -123,8 +125,13 @@ export type ReqTypes = { // It doesn't make sense to define a getReqSerializers() here given the exotic argument of eventstream() // The request is very simple: (topics) => {query: {topics}}, and the test will ensure compatibility server - client -export function getTypeByEvent(): {[K in EventType]: Type} { +export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: TypeJson} { const stringType = new StringType(); + const getLightClientOptimisticUpdateType = ( + data: allForks.LightClientOptimisticUpdate + ): allForks.AllForksLightClientSSZTypes["LightClientOptimisticUpdate"] => + config.getLightClientForkTypes(data.attestedHeader.beacon.slot).LightClientOptimisticUpdate; + return { [EventType.head]: new ContainerType( { @@ -178,14 +185,12 @@ export function getTypeByEvent(): {[K in EventType]: Type} { [EventType.contributionAndProof]: ssz.altair.SignedContributionAndProof, - [EventType.lightClientOptimisticUpdate]: new ContainerType( - { - syncAggregate: ssz.altair.SyncAggregate, - attestedHeader: ssz.altair.LightClientHeader, - signatureSlot: ssz.Slot, - }, - {jsonCase: "eth2"} - ), + [EventType.lightClientOptimisticUpdate]: { + toJson: (data) => + getLightClientOptimisticUpdateType((data as unknown) as allForks.LightClientOptimisticUpdate).toJson(data), + fromJson: (data) => + getLightClientOptimisticUpdateType((data as unknown) as allForks.LightClientOptimisticUpdate).fromJson(data), + }, [EventType.lightClientFinalityUpdate]: new ContainerType( { attestedHeader: ssz.altair.LightClientHeader, @@ -201,8 +206,8 @@ export function getTypeByEvent(): {[K in EventType]: Type} { } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export function getEventSerdes() { - const typeByEvent = getTypeByEvent(); +export function getEventSerdes(config: IChainForkConfig) { + const typeByEvent = getTypeByEvent(config); return { toJson: (event: BeaconEvent): unknown => { diff --git a/packages/api/src/beacon/server/events.ts b/packages/api/src/beacon/server/events.ts index 4ee4b36b4133..1235ca980bdf 100644 --- a/packages/api/src/beacon/server/events.ts +++ b/packages/api/src/beacon/server/events.ts @@ -4,7 +4,7 @@ import {ServerRoutes} from "../../utils/server/index.js"; import {ServerApi} from "../../interfaces.js"; export function getRoutes(config: IChainForkConfig, api: ServerApi): ServerRoutes { - const eventSerdes = getEventSerdes(); + const eventSerdes = getEventSerdes(config); return { // Non-JSON route. Server Sent Events (SSE) From 3f5c627de3985d201adada1a1f529c8957101465 Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 19:39:48 +0530 Subject: [PATCH 06/25] make lightclient routes multifork --- packages/api/src/beacon/routes/lightclient.ts | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/packages/api/src/beacon/routes/lightclient.ts b/packages/api/src/beacon/routes/lightclient.ts index df32efd08252..e3defa3dec1a 100644 --- a/packages/api/src/beacon/routes/lightclient.ts +++ b/packages/api/src/beacon/routes/lightclient.ts @@ -1,6 +1,5 @@ -import {altair, ssz, StringType, SyncPeriod} from "@lodestar/types"; -import {ForkName} from "@lodestar/params"; -import {ContainerType} from "@chainsafe/ssz"; +import {ssz, SyncPeriod, allForks} from "@lodestar/types"; +import {ForkName, isForkLightClient} from "@lodestar/params"; import { ArrayOf, ReturnTypes, @@ -17,13 +16,6 @@ import {ApiClientResponse} from "../../interfaces.js"; // See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes -export type LightClientBootstrap = { - header: altair.LightClientHeader; - currentSyncCommittee: altair.SyncCommittee; - /** Single branch proof from state root to currentSyncCommittee */ - currentSyncCommitteeBranch: Uint8Array[]; -}; - export type Api = { /** * Returns an array of best updates given a `startPeriod` and `count` number of sync committee period to return. @@ -39,7 +31,7 @@ export type Api = { ApiClientResponse<{ [HttpStatusCode.OK]: { version: ForkName; - data: altair.LightClientUpdate; + data: allForks.LightClientUpdate; }[]; }> >; @@ -51,7 +43,7 @@ export type Api = { ApiClientResponse<{ [HttpStatusCode.OK]: { version: ForkName; - data: altair.LightClientOptimisticUpdate; + data: allForks.LightClientOptimisticUpdate; }; }> >; @@ -59,7 +51,7 @@ export type Api = { ApiClientResponse<{ [HttpStatusCode.OK]: { version: ForkName; - data: altair.LightClientFinalityUpdate; + data: allForks.LightClientFinalityUpdate; }; }> >; @@ -74,7 +66,7 @@ export type Api = { ApiClientResponse<{ [HttpStatusCode.OK]: { version: ForkName; - data: altair.LightClientBootstrap; + data: allForks.LightClientBootstrap; }; }> >; @@ -138,16 +130,31 @@ export function getReqSerializers(): ReqSerializers { } export function getReturnTypes(): ReturnTypes { + // Form a TypeJson convertor for getUpdates + const VersionedUpdate = WithVersion((fork: ForkName) => + isForkLightClient(fork) ? ssz.allForksLightClient[fork].LightClientUpdate : ssz.altair.LightClientUpdate + ); + const getUpdates = { + toJson: (updates: {version: ForkName; data: allForks.LightClientUpdate}[]) => + updates.map((data) => VersionedUpdate.toJson(data)), + fromJson: (updates: unknown[]) => updates.map((data) => VersionedUpdate.fromJson(data)), + }; + return { - getUpdates: ArrayOf( - new ContainerType({ - version: new StringType(), - data: ssz.altair.LightClientUpdate, - }) + getUpdates, + getOptimisticUpdate: WithVersion((fork: ForkName) => + isForkLightClient(fork) + ? ssz.allForksLightClient[fork].LightClientOptimisticUpdate + : ssz.altair.LightClientOptimisticUpdate + ), + getFinalityUpdate: WithVersion((fork: ForkName) => + isForkLightClient(fork) + ? ssz.allForksLightClient[fork].LightClientFinalityUpdate + : ssz.altair.LightClientFinalityUpdate + ), + getBootstrap: WithVersion((fork: ForkName) => + isForkLightClient(fork) ? ssz.allForksLightClient[fork].LightClientBootstrap : ssz.altair.LightClientBootstrap ), - getOptimisticUpdate: WithVersion(() => ssz.altair.LightClientOptimisticUpdate), - getFinalityUpdate: WithVersion(() => ssz.altair.LightClientFinalityUpdate), - getBootstrap: WithVersion(() => ssz.altair.LightClientBootstrap), getCommitteeRoot: ContainerData(ArrayOf(ssz.Root)), }; } From ededf62fe80bdbb3b05e0e49b0ac266970d50b5c Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 20:10:01 +0530 Subject: [PATCH 07/25] update light-client transport --- packages/light-client/src/transport/interface.ts | 14 +++++++------- packages/light-client/src/transport/rest.ts | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/light-client/src/transport/interface.ts b/packages/light-client/src/transport/interface.ts index cc3038f57e3f..dcd3210df70c 100644 --- a/packages/light-client/src/transport/interface.ts +++ b/packages/light-client/src/transport/interface.ts @@ -1,4 +1,4 @@ -import {altair, SyncPeriod} from "@lodestar/types"; +import {allForks, SyncPeriod} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; export interface LightClientTransport { @@ -8,24 +8,24 @@ export interface LightClientTransport { ): Promise< { version: ForkName; - data: altair.LightClientUpdate; + data: allForks.LightClientUpdate; }[] >; /** * Returns the latest optimistic head update available. Clients should use the SSE type `light_client_optimistic_update` * unless to get the very first head update after syncing, or if SSE are not supported by the server. */ - getOptimisticUpdate(): Promise<{version: ForkName; data: altair.LightClientOptimisticUpdate}>; - getFinalityUpdate(): Promise<{version: ForkName; data: altair.LightClientFinalityUpdate}>; + getOptimisticUpdate(): Promise<{version: ForkName; data: allForks.LightClientOptimisticUpdate}>; + getFinalityUpdate(): Promise<{version: ForkName; data: allForks.LightClientFinalityUpdate}>; /** * Fetch a bootstrapping state with a proof to a trusted block root. * The trusted block root should be fetched with similar means to a weak subjectivity checkpoint. * Only block roots for checkpoints are guaranteed to be available. */ - getBootstrap(blockRoot: string): Promise<{version: ForkName; data: altair.LightClientBootstrap}>; + getBootstrap(blockRoot: string): Promise<{version: ForkName; data: allForks.LightClientBootstrap}>; // registers handler for LightClientOptimisticUpdate. This can come either via sse or p2p - onOptimisticUpdate(handler: (optimisticUpdate: altair.LightClientOptimisticUpdate) => void): void; + onOptimisticUpdate(handler: (optimisticUpdate: allForks.LightClientOptimisticUpdate) => void): void; // registers handler for LightClientFinalityUpdate. This can come either via sse or p2p - onFinalityUpdate(handler: (finalityUpdate: altair.LightClientFinalityUpdate) => void): void; + onFinalityUpdate(handler: (finalityUpdate: allForks.LightClientFinalityUpdate) => void): void; } diff --git a/packages/light-client/src/transport/rest.ts b/packages/light-client/src/transport/rest.ts index da65def2766c..9227da671369 100644 --- a/packages/light-client/src/transport/rest.ts +++ b/packages/light-client/src/transport/rest.ts @@ -6,8 +6,8 @@ import {ForkName} from "@lodestar/params"; import {LightClientTransport} from "./interface.js"; export type LightClientRestEvents = { - [routes.events.EventType.lightClientFinalityUpdate]: altair.LightClientFinalityUpdate; - [routes.events.EventType.lightClientOptimisticUpdate]: altair.LightClientOptimisticUpdate; + [routes.events.EventType.lightClientFinalityUpdate]: allForks.LightClientFinalityUpdate; + [routes.events.EventType.lightClientOptimisticUpdate]: allForks.LightClientOptimisticUpdate; }; type RestEvents = StrictEventEmitter; @@ -27,7 +27,7 @@ export class LightClientRestTransport extends (EventEmitter as {new (): RestEven ): Promise< { version: ForkName; - data: altair.LightClientUpdate; + data: allForks.LightClientUpdate; }[] > { const res = await this.api.lightclient.getUpdates(startPeriod, count); @@ -35,19 +35,19 @@ export class LightClientRestTransport extends (EventEmitter as {new (): RestEven return res.response; } - async getOptimisticUpdate(): Promise<{version: ForkName; data: altair.LightClientOptimisticUpdate}> { + async getOptimisticUpdate(): Promise<{version: ForkName; data: allForks.LightClientOptimisticUpdate}> { const res = await this.api.lightclient.getOptimisticUpdate(); ApiError.assert(res); return res.response; } - async getFinalityUpdate(): Promise<{version: ForkName; data: altair.LightClientFinalityUpdate}> { + async getFinalityUpdate(): Promise<{version: ForkName; data: allForks.LightClientFinalityUpdate}> { const res = await this.api.lightclient.getFinalityUpdate(); ApiError.assert(res); return res.response; } - async getBootstrap(blockRoot: string): Promise<{version: ForkName; data: altair.LightClientBootstrap}> { + async getBootstrap(blockRoot: string): Promise<{version: ForkName; data: allForks.LightClientBootstrap}> { const res = await this.api.lightclient.getBootstrap(blockRoot); ApiError.assert(res); return res.response; @@ -59,12 +59,12 @@ export class LightClientRestTransport extends (EventEmitter as {new (): RestEven return res.response; } - onOptimisticUpdate(handler: (optimisticUpdate: altair.LightClientOptimisticUpdate) => void): void { + onOptimisticUpdate(handler: (optimisticUpdate: allForks.LightClientOptimisticUpdate) => void): void { this.subscribeEventstream(); this.eventEmitter.on(routes.events.EventType.lightClientOptimisticUpdate, handler); } - onFinalityUpdate(handler: (finalityUpdate: altair.LightClientFinalityUpdate) => void): void { + onFinalityUpdate(handler: (finalityUpdate: allForks.LightClientFinalityUpdate) => void): void { this.subscribeEventstream(); this.eventEmitter.on(routes.events.EventType.lightClientFinalityUpdate, handler); } From 6a991b810aef42008e596491c0be8c311e442463 Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 20 Jan 2023 22:02:29 +0530 Subject: [PATCH 08/25] upgrade the blocktype on lightclient server import block --- packages/beacon-node/src/chain/blocks/importBlock.ts | 4 ++-- packages/beacon-node/src/chain/lightClient/index.ts | 8 ++++++-- packages/types/src/allForks/sszTypes.ts | 4 ++++ packages/types/src/allForks/types.ts | 9 +++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 305245863675..b24667041cd3 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -1,4 +1,4 @@ -import {altair, capella, ssz} from "@lodestar/types"; +import {capella, ssz, allForks} from "@lodestar/types"; import {MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params"; import {toHexString} from "@chainsafe/ssz"; import { @@ -275,7 +275,7 @@ export async function importBlock( if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) { try { this.lightClientServer.onImportBlockHead( - block.message as altair.BeaconBlock, + block.message as allForks.AllForksLightClient["BeaconBlock"], postState as CachedBeaconStateAltair, parentBlockSlot ); diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 87c539f9e04c..e3b7dd27e8eb 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -1,4 +1,4 @@ -import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod} from "@lodestar/types"; +import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod, allForks} from "@lodestar/types"; import {IChainForkConfig} from "@lodestar/config"; import { CachedBeaconStateAltair, @@ -212,7 +212,11 @@ export class LightClientServer { * - Persist state witness * - Use block's syncAggregate */ - onImportBlockHead(block: altair.BeaconBlock, postState: CachedBeaconStateAltair, parentBlockSlot: Slot): void { + onImportBlockHead( + block: allForks.AllForksLightClient["BeaconBlock"], + postState: CachedBeaconStateAltair, + parentBlockSlot: Slot + ): 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. // While this function is only called for head blocks, best to disable. diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 4ec3b4271f18..5e362cf8e6cf 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -108,6 +108,7 @@ export const allForksBlinded = { export const allForksLightClient = { altair: { + BeaconBlock: altair.BeaconBlock, LightClientHeader: altair.LightClientHeader, LightClientBootstrap: altair.LightClientBootstrap, LightClientUpdate: altair.LightClientUpdate, @@ -116,6 +117,7 @@ export const allForksLightClient = { LightClientStore: altair.LightClientStore, }, bellatrix: { + BeaconBlock: bellatrix.BeaconBlock, LightClientHeader: altair.LightClientHeader, LightClientBootstrap: altair.LightClientBootstrap, LightClientUpdate: altair.LightClientUpdate, @@ -124,6 +126,7 @@ export const allForksLightClient = { LightClientStore: altair.LightClientStore, }, capella: { + BeaconBlock: capella.BeaconBlock, LightClientHeader: capella.LightClientHeader, LightClientBootstrap: capella.LightClientBootstrap, LightClientUpdate: capella.LightClientUpdate, @@ -132,6 +135,7 @@ export const allForksLightClient = { LightClientStore: capella.LightClientStore, }, eip4844: { + BeaconBlock: eip4844.BeaconBlock, LightClientHeader: eip4844.LightClientHeader, LightClientBootstrap: eip4844.LightClientBootstrap, LightClientUpdate: eip4844.LightClientUpdate, diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index b858f5ee75dc..c05cdcfc6ef6 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -112,7 +112,13 @@ export type AllForksBlindedTypes = { }; export type AllForksLightClient = { + BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | eip4844.BeaconBlock; LightClientHeader: LightClientHeader; + LightClientBootstrap: LightClientBootstrap; + LightClientUpdate: LightClientUpdate; + LightClientFinalityUpdate: LightClientFinalityUpdate; + LightClientOptimisticUpdate: LightClientOptimisticUpdate; + LightClientStore: LightClientStore; }; /** @@ -222,6 +228,9 @@ export type AllForksBlindedSSZTypes = { }; export type AllForksLightClientSSZTypes = { + BeaconBlock: AllForksTypeOf< + typeof altairSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof eip4844Ssz.BeaconBlock + >; LightClientHeader: AllForksTypeOf< typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader >; From 1a53976c1b351ae230151ae93a22dc2bc300af19 Mon Sep 17 00:00:00 2001 From: gajinder Date: Thu, 2 Feb 2023 19:57:22 +0530 Subject: [PATCH 09/25] fixes --- packages/light-client/src/transport/rest.ts | 2 +- packages/light-client/test/utils/utils.ts | 5 ++--- packages/types/src/allForks/sszTypes.ts | 16 ++++++++-------- packages/types/src/allForks/types.ts | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/light-client/src/transport/rest.ts b/packages/light-client/src/transport/rest.ts index 9227da671369..2ac3cbc79ac0 100644 --- a/packages/light-client/src/transport/rest.ts +++ b/packages/light-client/src/transport/rest.ts @@ -1,6 +1,6 @@ import EventEmitter from "events"; import StrictEventEmitter from "strict-event-emitter-types"; -import {allForks, altair, SyncPeriod} from "@lodestar/types"; +import {allForks, SyncPeriod} from "@lodestar/types"; import {Api, ApiError, routes} from "@lodestar/api"; import {ForkName} from "@lodestar/params"; import {LightClientTransport} from "./interface.js"; diff --git a/packages/light-client/test/utils/utils.ts b/packages/light-client/test/utils/utils.ts index ad44cd85c8ec..8638e6f86180 100644 --- a/packages/light-client/test/utils/utils.ts +++ b/packages/light-client/test/utils/utils.ts @@ -2,7 +2,6 @@ import bls from "@chainsafe/bls/switchable"; import {PointFormat, PublicKey, SecretKey} from "@chainsafe/bls/types"; import {hash, Tree} from "@chainsafe/persistent-merkle-tree"; import {BitArray, fromHexString} from "@chainsafe/ssz"; -import {routes} from "@lodestar/api"; import {IBeaconConfig} from "@lodestar/config"; import { DOMAIN_SYNC_COMMITTEE, @@ -12,7 +11,7 @@ import { SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, } from "@lodestar/params"; -import {altair, phase0, Slot, ssz, SyncPeriod} from "@lodestar/types"; +import {altair, phase0, Slot, ssz, SyncPeriod, allForks} from "@lodestar/types"; import {SyncCommitteeFast} from "../../src/types.js"; import {computeSigningRoot} from "../../src/utils/domain.js"; import {getLcLoggerConsole} from "../../src/utils/logger.js"; @@ -159,7 +158,7 @@ export function computeLightclientUpdate(config: IBeaconConfig, period: SyncPeri export function computeLightClientSnapshot( period: SyncPeriod ): { - snapshot: routes.lightclient.LightClientBootstrap; + snapshot: allForks.LightClientBootstrap; checkpointRoot: Uint8Array; } { const currentSyncCommittee = getInteropSyncCommittee(period).syncCommittee; diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 5e362cf8e6cf..8730e92a3a86 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -134,14 +134,14 @@ export const allForksLightClient = { LightClientOptimisticUpdate: capella.LightClientOptimisticUpdate, LightClientStore: capella.LightClientStore, }, - eip4844: { - BeaconBlock: eip4844.BeaconBlock, - LightClientHeader: eip4844.LightClientHeader, - LightClientBootstrap: eip4844.LightClientBootstrap, - LightClientUpdate: eip4844.LightClientUpdate, - LightClientFinalityUpdate: eip4844.LightClientFinalityUpdate, - LightClientOptimisticUpdate: eip4844.LightClientOptimisticUpdate, - LightClientStore: eip4844.LightClientStore, + deneb: { + BeaconBlock: deneb.BeaconBlock, + LightClientHeader: deneb.LightClientHeader, + LightClientBootstrap: deneb.LightClientBootstrap, + LightClientUpdate: deneb.LightClientUpdate, + LightClientFinalityUpdate: deneb.LightClientFinalityUpdate, + LightClientOptimisticUpdate: deneb.LightClientOptimisticUpdate, + LightClientStore: deneb.LightClientStore, }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index c05cdcfc6ef6..ab6378ec4e7d 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -112,7 +112,7 @@ export type AllForksBlindedTypes = { }; export type AllForksLightClient = { - BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | eip4844.BeaconBlock; + BeaconBlock: altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock; LightClientHeader: LightClientHeader; LightClientBootstrap: LightClientBootstrap; LightClientUpdate: LightClientUpdate; @@ -229,7 +229,7 @@ export type AllForksBlindedSSZTypes = { export type AllForksLightClientSSZTypes = { BeaconBlock: AllForksTypeOf< - typeof altairSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof eip4844Ssz.BeaconBlock + typeof altairSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock >; LightClientHeader: AllForksTypeOf< typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader From ccc59bb8383dfb1ce285ce1fbadd5c329a9e8d1e Mon Sep 17 00:00:00 2001 From: gajinder Date: Thu, 2 Feb 2023 20:04:35 +0530 Subject: [PATCH 10/25] fix test --- packages/api/test/unit/beacon/oapiSpec.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index c95de6a33196..381e852a5add 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -110,7 +110,7 @@ describe("eventstream event data", () => { } }); - const eventSerdes = routes.events.getEventSerdes(); + const eventSerdes = routes.events.getEventSerdes(config); const knownTopics = new Set(Object.values(routes.events.eventTypes)); for (const [topic, {value}] of Object.entries(eventstreamExamples ?? {})) { From a6fedc15546337a3de1c2ab3790002eb7c10d4a4 Mon Sep 17 00:00:00 2001 From: gajinder Date: Thu, 2 Feb 2023 22:55:55 +0530 Subject: [PATCH 11/25] fix event serialization/deserilization type --- packages/api/src/beacon/routes/events.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index a7ed174c5479..082b20140c0a 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -128,9 +128,10 @@ export type ReqTypes = { export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: TypeJson} { const stringType = new StringType(); const getLightClientOptimisticUpdateType = ( - data: allForks.LightClientOptimisticUpdate - ): allForks.AllForksLightClientSSZTypes["LightClientOptimisticUpdate"] => - config.getLightClientForkTypes(data.attestedHeader.beacon.slot).LightClientOptimisticUpdate; + data: allForks.LightClientHeader + ): allForks.AllForksLightClientSSZTypes["LightClientOptimisticUpdate"] => { + return config.getLightClientForkTypes(data.beacon.slot).LightClientOptimisticUpdate; + }; return { [EventType.head]: new ContainerType( @@ -187,9 +188,14 @@ export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: Typ [EventType.lightClientOptimisticUpdate]: { toJson: (data) => - getLightClientOptimisticUpdateType((data as unknown) as allForks.LightClientOptimisticUpdate).toJson(data), + getLightClientOptimisticUpdateType( + ((data as unknown) as allForks.LightClientOptimisticUpdate).attestedHeader + ).toJson(data), fromJson: (data) => - getLightClientOptimisticUpdateType((data as unknown) as allForks.LightClientOptimisticUpdate).fromJson(data), + getLightClientOptimisticUpdateType( + // eslint-disable-next-line @typescript-eslint/naming-convention + ((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header + ).fromJson(data), }, [EventType.lightClientFinalityUpdate]: new ContainerType( { From c6fdf4c3aad5f79da6f1343135180cfa6a691d9e Mon Sep 17 00:00:00 2001 From: gajinder Date: Thu, 2 Feb 2023 23:55:04 +0530 Subject: [PATCH 12/25] update proof constants --- packages/beacon-node/src/util/multifork.ts | 19 ++++++++++--------- packages/params/src/index.ts | 12 ++++++++---- packages/types/src/capella/sszTypes.ts | 2 +- packages/types/src/deneb/sszTypes.ts | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/beacon-node/src/util/multifork.ts b/packages/beacon-node/src/util/multifork.ts index e72e4e28fcdc..e3e7625d6070 100644 --- a/packages/beacon-node/src/util/multifork.ts +++ b/packages/beacon-node/src/util/multifork.ts @@ -55,17 +55,18 @@ export function getStateTypeFromBytes( } /** - * TODO: find correct position - * 8 + 32 = 40 - * ``` - * class BeaconState(Container): - * genesis_time: uint64 [fixed - 8 bytes] - * genesis_validators_root: Root [fixed - 32 bytes] - * slot: Slot [fixed - 8 bytes] + * First field in update is beacon, first field in beacon is slot + * + * update = { + * beacon: { + * slot + * ... + * } + * ... + * } * ... - * ``` */ -const SLOT_BYTES_POSITION_IN_LIGHTCLIENTUPDATE = 40; +const SLOT_BYTES_POSITION_IN_LIGHTCLIENTUPDATE = 0; export function getLightClientUpdateTypeFromBytes( config: IChainForkConfig, bytes: Buffer | Uint8Array diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 51b321cd839a..4a85f0210f9b 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -195,15 +195,19 @@ export const FINALIZED_ROOT_GINDEX = 105; export const FINALIZED_ROOT_DEPTH = 6; export const FINALIZED_ROOT_INDEX = 41; -// TODO: add correct values here -export const EXECUTION_PAYLOAD_GINDEX = 105; +/** + * ```ts + * types.ssz.capella.BeaconBlockBody.getPathInfo(['executionPayload']).gindex + * ``` + */ +export const BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX = 25; /** * ```ts * Math.floor(Math.log2(EXECUTION_PAYLOAD_GINDEX)) * ``` */ -export const EXECUTION_PAYLOAD_DEPTH = 6; -export const EXECUTION_PAYLOAD_INDEX = 41; +export const BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH = 4; +export const BLOCK_BODY_EXECUTION_PAYLOAD_INDEX = 12; /** * ```ts diff --git a/packages/types/src/capella/sszTypes.ts b/packages/types/src/capella/sszTypes.ts index 734032f9f88c..858de7d635bd 100644 --- a/packages/types/src/capella/sszTypes.ts +++ b/packages/types/src/capella/sszTypes.ts @@ -3,7 +3,7 @@ import { HISTORICAL_ROOTS_LIMIT, MAX_WITHDRAWALS_PER_PAYLOAD, MAX_BLS_TO_EXECUTION_CHANGES, - EXECUTION_PAYLOAD_DEPTH, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, } from "@lodestar/params"; diff --git a/packages/types/src/deneb/sszTypes.ts b/packages/types/src/deneb/sszTypes.ts index f7aff6efaf53..221fd0e5dc7d 100644 --- a/packages/types/src/deneb/sszTypes.ts +++ b/packages/types/src/deneb/sszTypes.ts @@ -5,7 +5,7 @@ import { MAX_BLOBS_PER_BLOCK, MAX_REQUEST_BLOCKS, BYTES_PER_FIELD_ELEMENT, - EXECUTION_PAYLOAD_DEPTH, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, } from "@lodestar/params"; From 0504710e7c459fa29aeea6f7b8d15a32b4076e2e Mon Sep 17 00:00:00 2001 From: gajinder Date: Fri, 3 Feb 2023 00:17:39 +0530 Subject: [PATCH 13/25] fix payload index --- packages/params/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 4a85f0210f9b..8809a6b80ada 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -207,7 +207,7 @@ export const BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX = 25; * ``` */ export const BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH = 4; -export const BLOCK_BODY_EXECUTION_PAYLOAD_INDEX = 12; +export const BLOCK_BODY_EXECUTION_PAYLOAD_INDEX = 9; /** * ```ts From 2512507bb2d14e2a3d55416bbb1d48ef28ca6cb9 Mon Sep 17 00:00:00 2001 From: gajinder Date: Sun, 5 Feb 2023 21:29:58 +0530 Subject: [PATCH 14/25] update the light client update generation to multi fork --- .../src/chain/lightClient/index.ts | 87 ++++++++++++------- .../src/chain/lightClient/proofs.ts | 12 ++- .../lightclientCheckpointHeader.ts | 18 +++- packages/beacon-node/src/util/multifork.ts | 25 ++++++ packages/types/src/allForks/types.ts | 8 ++ 5 files changed, 117 insertions(+), 33 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index e3b7dd27e8eb..e79e0ed52074 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -5,12 +5,14 @@ import { computeStartSlotAtEpoch, computeSyncPeriodAtEpoch, computeSyncPeriodAtSlot, + executionPayloadToPayloadHeader, } from "@lodestar/state-transition"; import {isBetterUpdate, toLightClientUpdateSummary, LightClientUpdateSummary} from "@lodestar/light-client/spec"; import {ILogger, MapDef, pruneSetToMax} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {BitArray, CompositeViewDU, toHexString} from "@chainsafe/ssz"; -import {MIN_SYNC_COMMITTEE_PARTICIPANTS, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {MIN_SYNC_COMMITTEE_PARTICIPANTS, SYNC_COMMITTEE_SIZE, ForkName, ForkSeq, ForkExecution} from "@lodestar/params"; + import {IBeaconDb} from "../../db/index.js"; import {IMetrics} from "../../metrics/index.js"; import {ChainEventEmitter} from "../emitter.js"; @@ -22,6 +24,7 @@ import { getSyncCommitteesWitness, getFinalizedRootProof, getCurrentSyncCommitteeBranch, + getBlockBodyExecutionHeaderProof, } from "./proofs.js"; export type LightClientServerOpts = { @@ -32,7 +35,7 @@ type DependantRootHex = RootHex; type BlockRooHex = RootHex; export type SyncAttestedData = { - attestedHeader: phase0.BeaconBlockHeader; + attestedHeader: allForks.LightClientHeader; /** Precomputed root to prevent re-hashing */ blockRoot: Uint8Array; } & ( @@ -170,11 +173,11 @@ export class LightClientServer { * Keep in memory since this data is very transient, not useful after a few slots */ private readonly prevHeadData = new Map(); - private checkpointHeaders = new Map(); + private checkpointHeaders = new Map(); private latestHeadUpdate: altair.LightClientOptimisticUpdate | null = null; private readonly zero: Pick; - private finalized: altair.LightClientFinalityUpdate | null = null; + private finalized: allForks.LightClientFinalityUpdate | null = null; constructor(private readonly opts: LightClientServerOpts, modules: LightClientServerModules) { const {config, db, metrics, emitter, logger} = modules; @@ -280,7 +283,7 @@ export class LightClientServer { } return { - header: {beacon: header}, + header, currentSyncCommittee, currentSyncCommitteeBranch: getCurrentSyncCommitteeBranch(syncCommitteeWitness), }; @@ -344,21 +347,14 @@ export class LightClientServer { } private async persistPostBlockImportData( - block: altair.BeaconBlock, + block: allForks.AllForksLightClient["BeaconBlock"], postState: CachedBeaconStateAltair, parentBlockSlot: Slot ): Promise { const blockSlot = block.slot; + const header = blockToLightClientHeader(this.config.getForkName(blockSlot), block); - const header: phase0.BeaconBlockHeader = { - slot: blockSlot, - proposerIndex: block.proposerIndex, - parentRoot: block.parentRoot, - stateRoot: block.stateRoot, - bodyRoot: this.config.getForkTypes(blockSlot).BeaconBlockBody.hashTreeRoot(block.body), - }; - - const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header); + const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header.beacon); const blockRootHex = toHexString(blockRoot); const syncCommitteeWitness = getSyncCommitteesWitness(postState); @@ -463,7 +459,8 @@ export class LightClientServer { return; } - const attestedPeriod = computeSyncPeriodAtSlot(attestedData.attestedHeader.slot); + const {attestedHeader, isFinalized} = attestedData; + const attestedPeriod = computeSyncPeriodAtSlot(attestedHeader.beacon.slot); if (syncPeriod !== attestedPeriod) { this.logger.debug("attested data period different than signature period", {syncPeriod, attestedPeriod}); this.metrics?.lightclientServer.onSyncAggregate.inc({event: "ignore_attested_period_diff"}); @@ -471,7 +468,7 @@ export class LightClientServer { } const headerUpdate: altair.LightClientOptimisticUpdate = { - attestedHeader: {beacon: attestedData.attestedHeader}, + attestedHeader, syncAggregate, signatureSlot, }; @@ -493,24 +490,24 @@ export class LightClientServer { // Persist latest best update for getLatestHeadUpdate() // TODO: Once SyncAggregate are constructed from P2P too, count bits to decide "best" - if (!this.latestHeadUpdate || attestedData.attestedHeader.slot > this.latestHeadUpdate.attestedHeader.beacon.slot) { + if (!this.latestHeadUpdate || attestedHeader.beacon.slot > this.latestHeadUpdate.attestedHeader.beacon.slot) { this.latestHeadUpdate = headerUpdate; this.metrics?.lightclientServer.onSyncAggregate.inc({event: "update_latest_head_update"}); } - if (attestedData.isFinalized) { + if (isFinalized) { const finalizedCheckpointRoot = attestedData.finalizedCheckpoint.root as Uint8Array; const finalizedHeader = await this.getFinalizedHeader(finalizedCheckpointRoot); if ( finalizedHeader && (!this.finalized || - finalizedHeader.slot > this.finalized.finalizedHeader.beacon.slot || + finalizedHeader.beacon.slot > this.finalized.finalizedHeader.beacon.slot || syncAggregateParticipation > sumBits(this.finalized.syncAggregate.syncCommitteeBits)) ) { this.finalized = { - attestedHeader: {beacon: attestedData.attestedHeader}, - finalizedHeader: {beacon: finalizedHeader}, + attestedHeader, + finalizedHeader, syncAggregate, finalityBranch: attestedData.finalityBranch, signatureSlot, @@ -528,7 +525,7 @@ export class LightClientServer { } catch (e) { this.logger.error( "Error updating best LightClientUpdate", - {syncPeriod, slot: attestedData.attestedHeader.slot, blockRoot: toHexString(attestedData.blockRoot)}, + {syncPeriod, slot: attestedHeader.beacon.slot, blockRoot: toHexString(attestedData.blockRoot)}, e as Error ); } @@ -545,13 +542,14 @@ export class LightClientServer { attestedData: SyncAttestedData ): Promise { const prevBestUpdate = await this.db.bestLightClientUpdate.get(syncPeriod); + const {attestedHeader} = attestedData; if (prevBestUpdate) { const prevBestUpdateSummary = toLightClientUpdateSummary(prevBestUpdate); const nextBestUpdate: LightClientUpdateSummary = { activeParticipants: sumBits(syncAggregate.syncCommitteeBits), - attestedHeaderSlot: attestedData.attestedHeader.slot, + attestedHeaderSlot: attestedHeader.beacon.slot, signatureSlot, // The actual finalizedHeader is fetched below. To prevent a DB read we approximate the actual slot. // If update is not finalized finalizedHeaderSlot does not matter (see is_better_update), so setting @@ -585,13 +583,17 @@ export class LightClientServer { let newUpdate: altair.LightClientUpdate; let isFinalized; - if (attestedData.isFinalized && finalizedHeader && computeSyncPeriodAtSlot(finalizedHeader.slot) == syncPeriod) { + if ( + attestedData.isFinalized && + finalizedHeader && + computeSyncPeriodAtSlot(finalizedHeader.beacon.slot) == syncPeriod + ) { isFinalized = true; newUpdate = { - attestedHeader: {beacon: attestedData.attestedHeader}, + attestedHeader, nextSyncCommittee: nextSyncCommittee, nextSyncCommitteeBranch, - finalizedHeader: {beacon: finalizedHeader}, + finalizedHeader, finalityBranch: attestedData.finalityBranch, syncAggregate, signatureSlot, @@ -599,7 +601,7 @@ export class LightClientServer { } else { isFinalized = false; newUpdate = { - attestedHeader: {beacon: attestedData.attestedHeader}, + attestedHeader, nextSyncCommittee: nextSyncCommittee, nextSyncCommitteeBranch, finalizedHeader: this.zero.finalizedHeader, @@ -643,7 +645,7 @@ export class LightClientServer { /** * Get finalized header from db. Keeps a small in-memory cache to speed up most of the lookups */ - private async getFinalizedHeader(finalizedBlockRoot: Uint8Array): Promise { + private async getFinalizedHeader(finalizedBlockRoot: Uint8Array): Promise { const finalizedBlockRootHex = toHexString(finalizedBlockRoot); const cachedFinalizedHeader = this.checkpointHeaders.get(finalizedBlockRootHex); if (cachedFinalizedHeader) { @@ -670,3 +672,30 @@ export class LightClientServer { export function sumBits(bits: BitArray): number { return bits.getTrueBitIndexes().length; } + +export function blockToLightClientHeader( + fork: ForkName, + block: allForks.AllForksLightClient["BeaconBlock"] +): allForks.LightClientHeader { + const blockSlot = block.slot; + const beacon: phase0.BeaconBlockHeader = { + slot: blockSlot, + proposerIndex: block.proposerIndex, + parentRoot: block.parentRoot, + stateRoot: block.stateRoot, + bodyRoot: (ssz[fork].BeaconBlockBody as allForks.AllForksLightClientSSZTypes["BeaconBlockBody"]).hashTreeRoot( + block.body + ), + }; + if (ForkSeq[fork] >= ForkSeq.capella) { + const blockBody = block.body as allForks.AllForksExecution["BeaconBlockBody"]; + const execution = executionPayloadToPayloadHeader(ForkSeq[fork], blockBody.executionPayload); + return { + beacon, + execution, + executionBranch: getBlockBodyExecutionHeaderProof(fork as ForkExecution, blockBody), + } as allForks.LightClientHeader; + } else { + return {beacon}; + } +} diff --git a/packages/beacon-node/src/chain/lightClient/proofs.ts b/packages/beacon-node/src/chain/lightClient/proofs.ts index 633dcba9c308..6f68e0eae7c4 100644 --- a/packages/beacon-node/src/chain/lightClient/proofs.ts +++ b/packages/beacon-node/src/chain/lightClient/proofs.ts @@ -1,6 +1,8 @@ import {BeaconStateAllForks} from "@lodestar/state-transition"; -import {FINALIZED_ROOT_GINDEX} from "@lodestar/params"; +import {FINALIZED_ROOT_GINDEX, BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX, ForkExecution} from "@lodestar/params"; +import {allForks, ssz} from "@lodestar/types"; import {Tree} from "@chainsafe/persistent-merkle-tree"; + import {SyncCommitteeWitness} from "./types.js"; export function getSyncCommitteesWitness(state: BeaconStateAllForks): SyncCommitteeWitness { @@ -42,3 +44,11 @@ export function getFinalizedRootProof(state: BeaconStateAllForks): Uint8Array[] state.commit(); return new Tree(state.node).getSingleProof(BigInt(FINALIZED_ROOT_GINDEX)); } + +export function getBlockBodyExecutionHeaderProof( + fork: ForkExecution, + body: allForks.AllForksExecution["BeaconBlockBody"] +): Uint8Array[] { + const bodyView = (ssz[fork].BeaconBlockBody as allForks.AllForksExecutionSSZTypes["BeaconBlockBody"]).toView(body); + return new Tree(bodyView.node).getSingleProof(BigInt(BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX)); +} diff --git a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts index 907e964e67c3..e80ec9d1fe1a 100644 --- a/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts +++ b/packages/beacon-node/src/db/repositories/lightclientCheckpointHeader.ts @@ -1,6 +1,8 @@ import {IChainForkConfig} from "@lodestar/config"; import {Bucket, IDatabaseController, Repository} from "@lodestar/db"; -import {phase0, ssz} from "@lodestar/types"; +import {ssz, allForks} from "@lodestar/types"; + +import {getLightClientHeaderTypeFromBytes} from "../../util/multifork.js"; /** * Block headers by block root. Until finality includes all headers seen by this node. After finality, @@ -8,8 +10,18 @@ import {phase0, ssz} from "@lodestar/types"; * * Used to prepare light client updates */ -export class CheckpointHeaderRepository extends Repository { +export class CheckpointHeaderRepository extends Repository { constructor(config: IChainForkConfig, db: IDatabaseController) { - super(config, db, Bucket.lightClient_checkpointHeader, ssz.phase0.BeaconBlockHeader); + // Pick some type but won't be used + super(config, db, Bucket.lightClient_checkpointHeader, ssz.altair.LightClientHeader); + } + + // Overrides for multi-fork + encodeValue(value: allForks.LightClientHeader): Uint8Array { + return this.config.getLightClientForkTypes(value.beacon.slot).LightClientHeader.serialize(value) as Uint8Array; + } + + decodeValue(data: Uint8Array): allForks.LightClientHeader { + return getLightClientHeaderTypeFromBytes(this.config, data).deserialize(data); } } diff --git a/packages/beacon-node/src/util/multifork.ts b/packages/beacon-node/src/util/multifork.ts index e3e7625d6070..2f02fc6a5d30 100644 --- a/packages/beacon-node/src/util/multifork.ts +++ b/packages/beacon-node/src/util/multifork.ts @@ -58,10 +58,12 @@ export function getStateTypeFromBytes( * First field in update is beacon, first field in beacon is slot * * update = { + * attestedHeader: { * beacon: { * slot * ... * } + * } * ... * } * ... @@ -76,3 +78,26 @@ export function getLightClientUpdateTypeFromBytes( ); return config.getLightClientForkTypes(slot).LightClientUpdate; } + +/** + * First field in update is beacon, first field in beacon is slot + * + * update = { + * beacon: { + * slot + * ... + * } + * ... + * } + * ... + */ +const SLOT_BYTES_POSITION_IN_LIGHTCLIENTHEADER = 0; +export function getLightClientHeaderTypeFromBytes( + config: IChainForkConfig, + bytes: Buffer | Uint8Array +): allForks.AllForksLightClientSSZTypes["LightClientHeader"] { + const slot = bytesToInt( + bytes.subarray(SLOT_BYTES_POSITION_IN_LIGHTCLIENTHEADER, SLOT_BYTES_POSITION_IN_LIGHTCLIENTHEADER + SLOT_BYTE_COUNT) + ); + return config.getLightClientForkTypes(slot).LightClientHeader; +} diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index ab6378ec4e7d..3f078e51258a 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -121,6 +121,11 @@ export type AllForksLightClient = { LightClientStore: LightClientStore; }; +export type AllForksExecution = { + BeaconBlock: bellatrix.BeaconBlock | capella.BeaconBlock | deneb.BeaconBlock; + BeaconBlockBody: bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody; +}; + /** * An AllForks type must accept as any parameter the UNION of all fork types. * The generic argument of `AllForksTypeOf` must be the union of the fork types: @@ -231,6 +236,9 @@ export type AllForksLightClientSSZTypes = { BeaconBlock: AllForksTypeOf< typeof altairSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock >; + BeaconBlockBody: AllForksTypeOf< + typeof altairSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + >; LightClientHeader: AllForksTypeOf< typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader >; From 3d9dccd461e8a2c022d4c6847cbd7efed322669e Mon Sep 17 00:00:00 2001 From: gajinder Date: Sun, 5 Feb 2023 21:41:54 +0530 Subject: [PATCH 15/25] fix types --- packages/types/src/allForks/sszTypes.ts | 4 ++++ packages/types/src/allForks/types.ts | 10 ++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 8730e92a3a86..d55e45269e0e 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -109,6 +109,7 @@ export const allForksBlinded = { export const allForksLightClient = { altair: { BeaconBlock: altair.BeaconBlock, + BeaconBlockBody: altair.BeaconBlockBody, LightClientHeader: altair.LightClientHeader, LightClientBootstrap: altair.LightClientBootstrap, LightClientUpdate: altair.LightClientUpdate, @@ -118,6 +119,7 @@ export const allForksLightClient = { }, bellatrix: { BeaconBlock: bellatrix.BeaconBlock, + BeaconBlockBody: bellatrix.BeaconBlockBody, LightClientHeader: altair.LightClientHeader, LightClientBootstrap: altair.LightClientBootstrap, LightClientUpdate: altair.LightClientUpdate, @@ -127,6 +129,7 @@ export const allForksLightClient = { }, capella: { BeaconBlock: capella.BeaconBlock, + BeaconBlockBody: capella.BeaconBlockBody, LightClientHeader: capella.LightClientHeader, LightClientBootstrap: capella.LightClientBootstrap, LightClientUpdate: capella.LightClientUpdate, @@ -136,6 +139,7 @@ export const allForksLightClient = { }, deneb: { BeaconBlock: deneb.BeaconBlock, + BeaconBlockBody: deneb.BeaconBlockBody, LightClientHeader: deneb.LightClientHeader, LightClientBootstrap: deneb.LightClientBootstrap, LightClientUpdate: deneb.LightClientUpdate, diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 3f078e51258a..d03bb1e20d3d 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -234,10 +234,16 @@ export type AllForksBlindedSSZTypes = { export type AllForksLightClientSSZTypes = { BeaconBlock: AllForksTypeOf< - typeof altairSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof altairSsz.BeaconBlock + | typeof bellatrixSsz.BeaconBlock + | typeof capellaSsz.BeaconBlock + | typeof denebSsz.BeaconBlock >; BeaconBlockBody: AllForksTypeOf< - typeof altairSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof altairSsz.BeaconBlockBody + | typeof bellatrixSsz.BeaconBlockBody + | typeof capellaSsz.BeaconBlockBody + | typeof denebSsz.BeaconBlockBody >; LightClientHeader: AllForksTypeOf< typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader From 19b10d02016c74f24b2488612ccf8d1cc1fc99be Mon Sep 17 00:00:00 2001 From: gajinder Date: Sun, 5 Feb 2023 22:39:13 +0530 Subject: [PATCH 16/25] add spec override to pass specs --- .../test/spec/presets/index.test.ts | 32 ++++++++++++++++++- .../test/spec/presets/ssz_static.ts | 3 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/test/spec/presets/index.test.ts b/packages/beacon-node/test/spec/presets/index.test.ts index 052118f5681e..e48091692347 100644 --- a/packages/beacon-node/test/spec/presets/index.test.ts +++ b/packages/beacon-node/test/spec/presets/index.test.ts @@ -1,5 +1,8 @@ import path from "node:path"; import {ACTIVE_PRESET} from "@lodestar/params"; +import {Type} from "@chainsafe/ssz"; +import {ssz} from "@lodestar/types"; + import {RunnerType} from "../utils/types.js"; import {SkipOpts, specTestIterator} from "../utils/specTestIterator.js"; import {ethereumConsensusSpecsTests} from "../specTestVersioning.js"; @@ -32,6 +35,33 @@ const skipOpts: SkipOpts = {}; /* eslint-disable @typescript-eslint/naming-convention */ +// TODO: capella +// Map all lightclient types to altair for addressing the specs +// which are are to be updated in separate PR +const overrideSSZTypes: Record>> = { + deneb: { + LightClientHeader: ssz.altair.LightClientHeader, + LightClientUpdate: ssz.altair.LightClientUpdate, + LightClientOptimisticUpdate: ssz.altair.LightClientOptimisticUpdate, + LightClientFinalityUpdate: ssz.altair.LightClientFinalityUpdate, + LightClientBootstrap: ssz.altair.LightClientBootstrap, + }, + capella: { + LightClientHeader: ssz.altair.LightClientHeader, + LightClientUpdate: ssz.altair.LightClientUpdate, + LightClientOptimisticUpdate: ssz.altair.LightClientOptimisticUpdate, + LightClientFinalityUpdate: ssz.altair.LightClientFinalityUpdate, + LightClientBootstrap: ssz.altair.LightClientBootstrap, + }, + bellatrix: { + LightClientHeader: ssz.altair.LightClientHeader, + LightClientUpdate: ssz.altair.LightClientUpdate, + LightClientOptimisticUpdate: ssz.altair.LightClientOptimisticUpdate, + LightClientFinalityUpdate: ssz.altair.LightClientFinalityUpdate, + LightClientBootstrap: ssz.altair.LightClientBootstrap, + }, +}; + specTestIterator( path.join(ethereumConsensusSpecsTests.outputDir, "tests", ACTIVE_PRESET), { @@ -57,7 +87,7 @@ specTestIterator( shuffling: {type: RunnerType.default, fn: shuffling}, ssz_static: { type: RunnerType.custom, - fn: sszStatic(), + fn: sszStatic(undefined, overrideSSZTypes), }, sync: {type: RunnerType.default, fn: forkChoiceTest({onlyPredefinedResponses: true})}, transition: { diff --git a/packages/beacon-node/test/spec/presets/ssz_static.ts b/packages/beacon-node/test/spec/presets/ssz_static.ts index 17e9d342cf9c..599dd1587020 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.ts @@ -26,7 +26,7 @@ type Types = Record>; // tests / mainnet / altair / ssz_static / Validator / ssz_random / case_0/roots.yaml // -export const sszStatic = (skippedTypes?: string[]) => ( +export const sszStatic = (skippedTypes?: string[], overrideSSZTypes?: Record) => ( fork: ForkName, typeName: string, testSuite: string, @@ -39,6 +39,7 @@ export const sszStatic = (skippedTypes?: string[]) => ( /* eslint-disable @typescript-eslint/strict-boolean-expressions */ const sszType = + (((overrideSSZTypes ?? {})[fork] ?? {}) as Types)[typeName] || (ssz[fork] as Types)[typeName] || (ssz.capella as Types)[typeName] || (ssz.bellatrix as Types)[typeName] || From d60f342278b8471988e648850480ce0ebce4bcb3 Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 6 Feb 2023 16:35:39 +0530 Subject: [PATCH 17/25] make event types allforks --- packages/api/src/beacon/routes/events.ts | 52 ++++++++++++++---------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 082b20140c0a..f553a3202551 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -1,6 +1,5 @@ import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64, allForks} from "@lodestar/types"; -import {ContainerType, VectorCompositeType} from "@chainsafe/ssz"; -import {FINALIZED_ROOT_DEPTH} from "@lodestar/params"; +import {ContainerType} from "@chainsafe/ssz"; import {IChainForkConfig} from "@lodestar/config"; import {RouteDef, TypeJson} from "../../utils/index.js"; @@ -127,10 +126,8 @@ export type ReqTypes = { export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: TypeJson} { const stringType = new StringType(); - const getLightClientOptimisticUpdateType = ( - data: allForks.LightClientHeader - ): allForks.AllForksLightClientSSZTypes["LightClientOptimisticUpdate"] => { - return config.getLightClientForkTypes(data.beacon.slot).LightClientOptimisticUpdate; + const getLightClientTypeFromHeader = (data: allForks.LightClientHeader): allForks.AllForksLightClientSSZTypes => { + return config.getLightClientForkTypes(data.beacon.slot); }; return { @@ -188,26 +185,37 @@ export function getTypeByEvent(config: IChainForkConfig): {[K in EventType]: Typ [EventType.lightClientOptimisticUpdate]: { toJson: (data) => - getLightClientOptimisticUpdateType( - ((data as unknown) as allForks.LightClientOptimisticUpdate).attestedHeader - ).toJson(data), + getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientOptimisticUpdate).attestedHeader)[ + "LightClientOptimisticUpdate" + ].toJson(data), fromJson: (data) => - getLightClientOptimisticUpdateType( + getLightClientTypeFromHeader( // eslint-disable-next-line @typescript-eslint/naming-convention ((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header - ).fromJson(data), + )["LightClientOptimisticUpdate"].fromJson(data), + }, + [EventType.lightClientFinalityUpdate]: { + toJson: (data) => + getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientFinalityUpdate).attestedHeader)[ + "LightClientFinalityUpdate" + ].toJson(data), + fromJson: (data) => + getLightClientTypeFromHeader( + // eslint-disable-next-line @typescript-eslint/naming-convention + ((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header + )["LightClientFinalityUpdate"].fromJson(data), + }, + [EventType.lightClientUpdate]: { + toJson: (data) => + getLightClientTypeFromHeader(((data as unknown) as allForks.LightClientUpdate).attestedHeader)[ + "LightClientUpdate" + ].toJson(data), + fromJson: (data) => + getLightClientTypeFromHeader( + // eslint-disable-next-line @typescript-eslint/naming-convention + ((data as unknown) as {attested_header: allForks.LightClientHeader}).attested_header + )["LightClientUpdate"].fromJson(data), }, - [EventType.lightClientFinalityUpdate]: new ContainerType( - { - attestedHeader: ssz.altair.LightClientHeader, - finalizedHeader: ssz.altair.LightClientHeader, - finalityBranch: new VectorCompositeType(ssz.Bytes32, FINALIZED_ROOT_DEPTH), - syncAggregate: ssz.altair.SyncAggregate, - signatureSlot: ssz.Slot, - }, - {jsonCase: "eth2"} - ), - [EventType.lightClientUpdate]: ssz.altair.LightClientUpdate, }; } From 1418c0a5e1c782a79b649aa7605df334b7082b2c Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 6 Feb 2023 17:51:10 +0530 Subject: [PATCH 18/25] make req/resp multifork --- packages/reqresp/src/protocols/LightClientBootstrap.ts | 10 +++++++--- .../reqresp/src/protocols/LightClientFinalityUpdate.ts | 10 +++++++--- .../src/protocols/LightClientOptimisticUpdate.ts | 10 +++++++--- .../reqresp/src/protocols/LightClientUpdatesByRange.ts | 9 +++++---- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/reqresp/src/protocols/LightClientBootstrap.ts b/packages/reqresp/src/protocols/LightClientBootstrap.ts index 07d60db63d80..b4ae6fac4096 100644 --- a/packages/reqresp/src/protocols/LightClientBootstrap.ts +++ b/packages/reqresp/src/protocols/LightClientBootstrap.ts @@ -1,10 +1,11 @@ -import {altair, Root, ssz} from "@lodestar/types"; +import {Root, ssz, allForks} from "@lodestar/types"; +import {isForkLightClient} from "@lodestar/params"; import {toHex} from "@lodestar/utils"; import {Encoding, ProtocolDefinitionGenerator} from "../types.js"; import {getContextBytesLightclient} from "./utils.js"; // eslint-disable-next-line @typescript-eslint/naming-convention -export const LightClientBootstrap: ProtocolDefinitionGenerator = ( +export const LightClientBootstrap: ProtocolDefinitionGenerator = ( modules, handler ) => { @@ -14,7 +15,10 @@ export const LightClientBootstrap: ProtocolDefinitionGenerator ssz.Root, - responseType: () => ssz.altair.LightClientBootstrap, + responseType: (forkName) => + isForkLightClient(forkName) + ? ssz.allForksLightClient[forkName].LightClientBootstrap + : ssz.altair.LightClientBootstrap, renderRequestBody: (req) => toHex(req), contextBytes: getContextBytesLightclient( (bootstrap) => modules.config.getForkName(bootstrap.header.beacon.slot), diff --git a/packages/reqresp/src/protocols/LightClientFinalityUpdate.ts b/packages/reqresp/src/protocols/LightClientFinalityUpdate.ts index e96c6c0d0fef..c3dcb5ce26c2 100644 --- a/packages/reqresp/src/protocols/LightClientFinalityUpdate.ts +++ b/packages/reqresp/src/protocols/LightClientFinalityUpdate.ts @@ -1,9 +1,10 @@ -import {altair, ssz} from "@lodestar/types"; +import {ssz, allForks} from "@lodestar/types"; +import {isForkLightClient} from "@lodestar/params"; import {Encoding, ProtocolDefinitionGenerator} from "../types.js"; import {getContextBytesLightclient} from "./utils.js"; // eslint-disable-next-line @typescript-eslint/naming-convention -export const LightClientFinalityUpdate: ProtocolDefinitionGenerator = ( +export const LightClientFinalityUpdate: ProtocolDefinitionGenerator = ( modules, handler ) => { @@ -13,7 +14,10 @@ export const LightClientFinalityUpdate: ProtocolDefinitionGenerator null, - responseType: () => ssz.altair.LightClientFinalityUpdate, + responseType: (forkName) => + isForkLightClient(forkName) + ? ssz.allForksLightClient[forkName].LightClientFinalityUpdate + : ssz.altair.LightClientFinalityUpdate, contextBytes: getContextBytesLightclient((update) => modules.config.getForkName(update.signatureSlot), modules), inboundRateLimits: { // Finality updates should not be requested more than once per epoch. diff --git a/packages/reqresp/src/protocols/LightClientOptimisticUpdate.ts b/packages/reqresp/src/protocols/LightClientOptimisticUpdate.ts index 19912a7708f4..ba97a92ece3e 100644 --- a/packages/reqresp/src/protocols/LightClientOptimisticUpdate.ts +++ b/packages/reqresp/src/protocols/LightClientOptimisticUpdate.ts @@ -1,9 +1,10 @@ -import {altair, ssz} from "@lodestar/types"; +import {ssz, allForks} from "@lodestar/types"; +import {isForkLightClient} from "@lodestar/params"; import {Encoding, ProtocolDefinitionGenerator} from "../types.js"; import {getContextBytesLightclient} from "./utils.js"; // eslint-disable-next-line @typescript-eslint/naming-convention -export const LightClientOptimisticUpdate: ProtocolDefinitionGenerator = ( +export const LightClientOptimisticUpdate: ProtocolDefinitionGenerator = ( modules, handler ) => { @@ -13,7 +14,10 @@ export const LightClientOptimisticUpdate: ProtocolDefinitionGenerator null, - responseType: () => ssz.altair.LightClientOptimisticUpdate, + responseType: (forkName) => + isForkLightClient(forkName) + ? ssz.allForksLightClient[forkName].LightClientOptimisticUpdate + : ssz.altair.LightClientOptimisticUpdate, contextBytes: getContextBytesLightclient((update) => modules.config.getForkName(update.signatureSlot), modules), inboundRateLimits: { // Optimistic updates should not be requested more than once per slot. diff --git a/packages/reqresp/src/protocols/LightClientUpdatesByRange.ts b/packages/reqresp/src/protocols/LightClientUpdatesByRange.ts index 74350e70a2cc..1f6594a6a7c3 100644 --- a/packages/reqresp/src/protocols/LightClientUpdatesByRange.ts +++ b/packages/reqresp/src/protocols/LightClientUpdatesByRange.ts @@ -1,12 +1,12 @@ -import {MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params"; -import {altair, ssz} from "@lodestar/types"; +import {MAX_REQUEST_LIGHT_CLIENT_UPDATES, isForkLightClient} from "@lodestar/params"; +import {altair, ssz, allForks} from "@lodestar/types"; import {Encoding, ProtocolDefinitionGenerator} from "../types.js"; import {getContextBytesLightclient} from "./utils.js"; // eslint-disable-next-line @typescript-eslint/naming-convention export const LightClientUpdatesByRange: ProtocolDefinitionGenerator< altair.LightClientUpdatesByRange, - altair.LightClientUpdate + allForks.LightClientUpdate > = (modules, handler) => { return { method: "light_client_updates_by_range", @@ -14,7 +14,8 @@ export const LightClientUpdatesByRange: ProtocolDefinitionGenerator< encoding: Encoding.SSZ_SNAPPY, handler, requestType: () => ssz.altair.LightClientUpdatesByRange, - responseType: () => ssz.altair.LightClientUpdate, + responseType: (forkName) => + isForkLightClient(forkName) ? ssz.allForksLightClient[forkName].LightClientUpdate : ssz.altair.LightClientUpdate, renderRequestBody: (req) => `${req.startPeriod},${req.count}`, contextBytes: getContextBytesLightclient((update) => modules.config.getForkName(update.signatureSlot), modules), inboundRateLimits: { From 15d2f6c1c1115fb11db079dadc6b5de499917f1d Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 6 Feb 2023 18:31:51 +0530 Subject: [PATCH 19/25] make types multifork throughout --- .../src/chain/lightClient/index.ts | 14 +++++----- .../validation/lightClientFinalityUpdate.ts | 12 ++++----- .../validation/lightClientOptimisticUpdate.ts | 14 +++++----- .../src/network/gossip/gossipsub.ts | 4 +-- .../src/network/gossip/interface.ts | 8 +++--- .../beacon-node/src/network/gossip/topic.ts | 16 +++++++++--- packages/beacon-node/src/network/network.ts | 6 ++--- .../src/network/reqresp/ReqRespBeaconNode.ts | 16 ++++++------ .../reqresp/handlers/lightClientBootstrap.ts | 4 +-- .../handlers/lightClientFinalityUpdate.ts | 4 +-- .../handlers/lightClientOptimisticUpdate.ts | 4 +-- .../handlers/lightClientUpdatesByRange.ts | 4 +-- .../src/network/reqresp/interface.ts | 8 +++--- packages/light-client/src/events.ts | 6 ++--- packages/light-client/src/index.ts | 12 ++++----- packages/light-client/src/spec/index.ts | 10 +++---- .../light-client/src/spec/isBetterUpdate.ts | 4 +-- .../src/spec/processLightClientUpdate.ts | 4 +-- packages/light-client/src/spec/store.ts | 26 +++++++++---------- packages/light-client/src/spec/utils.ts | 6 ++--- .../src/spec/validateLightClientBootstrap.ts | 4 +-- .../src/spec/validateLightClientUpdate.ts | 4 +-- packages/light-client/src/types.ts | 6 ++--- packages/light-client/src/validation.ts | 8 +++--- 24 files changed, 107 insertions(+), 97 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index e79e0ed52074..9aa939ac17d9 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -174,7 +174,7 @@ export class LightClientServer { */ private readonly prevHeadData = new Map(); private checkpointHeaders = new Map(); - private latestHeadUpdate: altair.LightClientOptimisticUpdate | null = null; + private latestHeadUpdate: allForks.LightClientOptimisticUpdate | null = null; private readonly zero: Pick; private finalized: allForks.LightClientFinalityUpdate | null = null; @@ -251,7 +251,7 @@ export class LightClientServer { /** * API ROUTE to get `currentSyncCommittee` and `nextSyncCommittee` from a trusted state root */ - async getBootstrap(blockRoot: Uint8Array): Promise { + async getBootstrap(blockRoot: Uint8Array): Promise { const syncCommitteeWitness = await this.db.syncCommitteeWitness.get(blockRoot); if (!syncCommitteeWitness) { throw new LightClientServerError( @@ -296,7 +296,7 @@ export class LightClientServer { * - Has the most bits * - Signed header at the oldest slot */ - async getUpdate(period: number): Promise { + async getUpdate(period: number): Promise { // Signature data const update = await this.db.bestLightClientUpdate.get(period); if (!update) { @@ -327,11 +327,11 @@ export class LightClientServer { * API ROUTE to poll LightclientHeaderUpdate. * Clients should use the SSE type `light_client_optimistic_update` if available */ - getOptimisticUpdate(): altair.LightClientOptimisticUpdate | null { + getOptimisticUpdate(): allForks.LightClientOptimisticUpdate | null { return this.latestHeadUpdate; } - getFinalityUpdate(): altair.LightClientFinalityUpdate | null { + getFinalityUpdate(): allForks.LightClientFinalityUpdate | null { return this.finalized; } @@ -467,7 +467,7 @@ export class LightClientServer { return; } - const headerUpdate: altair.LightClientOptimisticUpdate = { + const headerUpdate: allForks.LightClientOptimisticUpdate = { attestedHeader, syncAggregate, signatureSlot, @@ -581,7 +581,7 @@ export class LightClientServer { ? await this.getFinalizedHeader(attestedData.finalizedCheckpoint.root as Uint8Array) : null; - let newUpdate: altair.LightClientUpdate; + let newUpdate: allForks.LightClientUpdate; let isFinalized; if ( attestedData.isFinalized && diff --git a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts index edeef0a07149..afa274ee46d9 100644 --- a/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientFinalityUpdate.ts @@ -1,5 +1,5 @@ import {IChainForkConfig} from "@lodestar/config"; -import {altair, ssz} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; import {IBeaconChain} from "../interface.js"; import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js"; import {GossipAction} from "../errors/index.js"; @@ -9,7 +9,7 @@ import {updateReceivedTooEarly} from "./lightClientOptimisticUpdate.js"; export function validateLightClientFinalityUpdate( config: IChainForkConfig, chain: IBeaconChain, - gossipedFinalityUpdate: altair.LightClientFinalityUpdate + gossipedFinalityUpdate: allForks.LightClientFinalityUpdate ): void { // [IGNORE] No other finality_update with a lower or equal finalized_header.slot was already forwarded on the network const gossipedFinalitySlot = gossipedFinalityUpdate.finalizedHeader.beacon.slot; @@ -31,10 +31,10 @@ export function validateLightClientFinalityUpdate( } // [IGNORE] The received finality_update matches the locally computed one exactly - if ( - localFinalityUpdate === null || - !ssz.altair.LightClientFinalityUpdate.equals(gossipedFinalityUpdate, localFinalityUpdate) - ) { + const sszType = config.getLightClientForkTypes(gossipedFinalityUpdate.attestedHeader.beacon.slot)[ + "LightClientFinalityUpdate" + ]; + if (localFinalityUpdate === null || !sszType.equals(gossipedFinalityUpdate, localFinalityUpdate)) { throw new LightClientError(GossipAction.IGNORE, { code: LightClientErrorCode.FINALITY_UPDATE_NOT_MATCHING_LOCAL, }); diff --git a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts index 0d07d80fee47..123a1630f589 100644 --- a/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/chain/validation/lightClientOptimisticUpdate.ts @@ -1,4 +1,4 @@ -import {altair, ssz} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; import {IChainForkConfig} from "@lodestar/config"; import {computeTimeAtSlot} from "@lodestar/state-transition"; import {IBeaconChain} from "../interface.js"; @@ -10,7 +10,7 @@ import {MAXIMUM_GOSSIP_CLOCK_DISPARITY} from "../../constants/index.js"; export function validateLightClientOptimisticUpdate( config: IChainForkConfig, chain: IBeaconChain, - gossipedOptimisticUpdate: altair.LightClientOptimisticUpdate + gossipedOptimisticUpdate: allForks.LightClientOptimisticUpdate ): void { // [IGNORE] No other optimistic_update with a lower or equal attested_header.slot was already forwarded on the network const gossipedAttestedSlot = gossipedOptimisticUpdate.attestedHeader.beacon.slot; @@ -32,10 +32,10 @@ export function validateLightClientOptimisticUpdate( } // [IGNORE] The received optimistic_update matches the locally computed one exactly - if ( - localOptimisticUpdate === null || - !ssz.altair.LightClientOptimisticUpdate.equals(gossipedOptimisticUpdate, localOptimisticUpdate) - ) { + const sszType = config.getLightClientForkTypes(gossipedOptimisticUpdate.attestedHeader.beacon.slot)[ + "LightClientOptimisticUpdate" + ]; + if (localOptimisticUpdate === null || !sszType.equals(gossipedOptimisticUpdate, localOptimisticUpdate)) { throw new LightClientError(GossipAction.IGNORE, { code: LightClientErrorCode.OPTIMISTIC_UPDATE_NOT_MATCHING_LOCAL, }); @@ -56,7 +56,7 @@ export function validateLightClientOptimisticUpdate( export function updateReceivedTooEarly( config: IChainForkConfig, genesisTime: number, - update: Pick + update: Pick ): boolean { const signatureSlot13TimestampMs = computeTimeAtSlot(config, update.signatureSlot + 1 / 3, genesisTime) * 1000; const earliestAllowedTimestampMs = signatureSlot13TimestampMs - MAXIMUM_GOSSIP_CLOCK_DISPARITY; diff --git a/packages/beacon-node/src/network/gossip/gossipsub.ts b/packages/beacon-node/src/network/gossip/gossipsub.ts index 8b44d4499823..0cde08a57f81 100644 --- a/packages/beacon-node/src/network/gossip/gossipsub.ts +++ b/packages/beacon-node/src/network/gossip/gossipsub.ts @@ -265,7 +265,7 @@ export class Eth2Gossipsub extends GossipSub { ); } - async publishLightClientFinalityUpdate(lightClientFinalityUpdate: altair.LightClientFinalityUpdate): Promise { + async publishLightClientFinalityUpdate(lightClientFinalityUpdate: allForks.LightClientFinalityUpdate): Promise { const fork = this.config.getForkName(lightClientFinalityUpdate.signatureSlot); await this.publishObject( {type: GossipType.light_client_finality_update, fork}, @@ -274,7 +274,7 @@ export class Eth2Gossipsub extends GossipSub { } async publishLightClientOptimisticUpdate( - lightClientOptimisitcUpdate: altair.LightClientOptimisticUpdate + lightClientOptimisitcUpdate: allForks.LightClientOptimisticUpdate ): Promise { const fork = this.config.getForkName(lightClientOptimisitcUpdate.signatureSlot); await this.publishObject( diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index 61ae8e93073c..25972ac06146 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -75,8 +75,8 @@ export type GossipTypeMap = { [GossipType.attester_slashing]: phase0.AttesterSlashing; [GossipType.sync_committee_contribution_and_proof]: altair.SignedContributionAndProof; [GossipType.sync_committee]: altair.SyncCommitteeMessage; - [GossipType.light_client_finality_update]: altair.LightClientFinalityUpdate; - [GossipType.light_client_optimistic_update]: altair.LightClientOptimisticUpdate; + [GossipType.light_client_finality_update]: allForks.LightClientFinalityUpdate; + [GossipType.light_client_optimistic_update]: allForks.LightClientOptimisticUpdate; [GossipType.bls_to_execution_change]: capella.SignedBLSToExecutionChange; }; @@ -95,10 +95,10 @@ export type GossipFnByType = { ) => Promise | void; [GossipType.sync_committee]: (syncCommittee: altair.SyncCommitteeMessage) => Promise | void; [GossipType.light_client_finality_update]: ( - lightClientFinalityUpdate: altair.LightClientFinalityUpdate + lightClientFinalityUpdate: allForks.LightClientFinalityUpdate ) => Promise | void; [GossipType.light_client_optimistic_update]: ( - lightClientOptimisticUpdate: altair.LightClientOptimisticUpdate + lightClientOptimisticUpdate: allForks.LightClientOptimisticUpdate ) => Promise | void; [GossipType.bls_to_execution_change]: ( blsToExecutionChange: capella.SignedBLSToExecutionChange diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 650aa2b49d80..9c3ab74ac784 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -1,6 +1,12 @@ import {ssz} from "@lodestar/types"; import {IForkDigestContext} from "@lodestar/config"; -import {ATTESTATION_SUBNET_COUNT, ForkName, ForkSeq, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; +import { + ATTESTATION_SUBNET_COUNT, + ForkName, + ForkSeq, + SYNC_COMMITTEE_SUBNET_COUNT, + isForkLightClient, +} from "@lodestar/params"; import {GossipEncoding, GossipTopic, GossipType, GossipTopicTypeMap} from "./interface.js"; import {DEFAULT_ENCODING} from "./constants.js"; @@ -92,9 +98,13 @@ export function getGossipSSZType(topic: GossipTopic) { case GossipType.sync_committee: return ssz.altair.SyncCommitteeMessage; case GossipType.light_client_optimistic_update: - return ssz.altair.LightClientOptimisticUpdate; + return isForkLightClient(topic.fork) + ? ssz.allForksLightClient[topic.fork].LightClientOptimisticUpdate + : ssz.altair.LightClientOptimisticUpdate; case GossipType.light_client_finality_update: - return ssz.altair.LightClientFinalityUpdate; + return isForkLightClient(topic.fork) + ? ssz.allForksLightClient[topic.fork].LightClientFinalityUpdate + : ssz.altair.LightClientFinalityUpdate; case GossipType.bls_to_execution_change: return ssz.capella.SignedBLSToExecutionChange; } diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 60e115ec1907..daea6a9b1af5 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -6,7 +6,7 @@ import {ILogger, sleep} from "@lodestar/utils"; import {ATTESTATION_SUBNET_COUNT, ForkName, ForkSeq, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {SignableENR} from "@chainsafe/discv5"; import {computeEpochAtSlot, computeTimeAtSlot} from "@lodestar/state-transition"; -import {altair, deneb, Epoch, phase0} from "@lodestar/types"; +import {deneb, Epoch, phase0, allForks} from "@lodestar/types"; import {routes} from "@lodestar/api"; import {IMetrics} from "../metrics/index.js"; import {ChainEvent, IBeaconChain, IBeaconClock} from "../chain/index.js"; @@ -557,7 +557,7 @@ export class Network implements INetwork { } } - private onLightClientFinalityUpdate = async (finalityUpdate: altair.LightClientFinalityUpdate): Promise => { + private onLightClientFinalityUpdate = async (finalityUpdate: allForks.LightClientFinalityUpdate): Promise => { if (this.hasAttachedSyncCommitteeMember()) { try { // messages SHOULD be broadcast after one-third of slot has transpired @@ -575,7 +575,7 @@ export class Network implements INetwork { }; private onLightClientOptimisticUpdate = async ( - optimisticUpdate: altair.LightClientOptimisticUpdate + optimisticUpdate: allForks.LightClientOptimisticUpdate ): Promise => { if (this.hasAttachedSyncCommitteeMember()) { try { diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index 1929ed22e253..8334cddf2add 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -204,9 +204,9 @@ export class ReqRespBeaconNode extends ReqResp implements IReqRespBeaconNode { ); } - async lightClientBootstrap(peerId: PeerId, request: Root): Promise { + async lightClientBootstrap(peerId: PeerId, request: Root): Promise { return collectExactOne( - this.sendRequest( + this.sendRequest( peerId, ReqRespMethod.LightClientBootstrap, [Version.V1], @@ -215,9 +215,9 @@ export class ReqRespBeaconNode extends ReqResp implements IReqRespBeaconNode { ); } - async lightClientOptimisticUpdate(peerId: PeerId): Promise { + async lightClientOptimisticUpdate(peerId: PeerId): Promise { return collectExactOne( - this.sendRequest( + this.sendRequest( peerId, ReqRespMethod.LightClientOptimisticUpdate, [Version.V1], @@ -226,9 +226,9 @@ export class ReqRespBeaconNode extends ReqResp implements IReqRespBeaconNode { ); } - async lightClientFinalityUpdate(peerId: PeerId): Promise { + async lightClientFinalityUpdate(peerId: PeerId): Promise { return collectExactOne( - this.sendRequest( + this.sendRequest( peerId, ReqRespMethod.LightClientFinalityUpdate, [Version.V1], @@ -240,9 +240,9 @@ export class ReqRespBeaconNode extends ReqResp implements IReqRespBeaconNode { async lightClientUpdatesByRange( peerId: PeerId, request: altair.LightClientUpdatesByRange - ): Promise { + ): Promise { return collectMaxResponse( - this.sendRequest( + this.sendRequest( peerId, ReqRespMethod.LightClientUpdatesByRange, [Version.V1], diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts index 5ad51debea92..e49024b5a873 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientBootstrap.ts @@ -6,13 +6,13 @@ import { LightClientServerError, LightClientServerErrorCode, } from "@lodestar/reqresp"; -import {altair, Root} from "@lodestar/types"; +import {Root, allForks} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; export async function* onLightClientBootstrap( requestBody: Root, chain: IBeaconChain -): AsyncIterable> { +): AsyncIterable> { try { yield { type: EncodedPayloadType.ssz, diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts index 77bfab2cd16c..085f00c56fd6 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientFinalityUpdate.ts @@ -1,10 +1,10 @@ import {EncodedPayload, ResponseError, RespStatus, EncodedPayloadType} from "@lodestar/reqresp"; -import {altair} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; export async function* onLightClientFinalityUpdate( chain: IBeaconChain -): AsyncIterable> { +): AsyncIterable> { const finalityUpdate = chain.lightClientServer.getFinalityUpdate(); if (finalityUpdate === null) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, "No latest finality update available"); diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts index 8bfae7d0f61f..b23be775810e 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientOptimisticUpdate.ts @@ -1,10 +1,10 @@ import {EncodedPayload, EncodedPayloadType, ResponseError, RespStatus} from "@lodestar/reqresp"; -import {altair} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; import {IBeaconChain} from "../../../chain/index.js"; export async function* onLightClientOptimisticUpdate( chain: IBeaconChain -): AsyncIterable> { +): AsyncIterable> { const optimisticUpdate = chain.lightClientServer.getOptimisticUpdate(); if (optimisticUpdate === null) { throw new ResponseError(RespStatus.RESOURCE_UNAVAILABLE, "No latest optimistic update available"); diff --git a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts index d5ab43984a19..3e7150399874 100644 --- a/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts +++ b/packages/beacon-node/src/network/reqresp/handlers/lightClientUpdatesByRange.ts @@ -1,4 +1,4 @@ -import {altair} from "@lodestar/types"; +import {altair, allForks} from "@lodestar/types"; import {MAX_REQUEST_LIGHT_CLIENT_UPDATES} from "@lodestar/params"; import { EncodedPayload, @@ -13,7 +13,7 @@ import {IBeaconChain} from "../../../chain/index.js"; export async function* onLightClientUpdatesByRange( requestBody: altair.LightClientUpdatesByRange, chain: IBeaconChain -): AsyncIterable> { +): AsyncIterable> { const count = Math.min(MAX_REQUEST_LIGHT_CLIENT_UPDATES, requestBody.count); for (let period = requestBody.startPeriod; period < requestBody.startPeriod + count; period++) { try { diff --git a/packages/beacon-node/src/network/reqresp/interface.ts b/packages/beacon-node/src/network/reqresp/interface.ts index 2cb9529b5674..efcbc2dac94a 100644 --- a/packages/beacon-node/src/network/reqresp/interface.ts +++ b/packages/beacon-node/src/network/reqresp/interface.ts @@ -18,13 +18,13 @@ export interface IReqRespBeaconNode { peerId: PeerId, request: deneb.BeaconBlockAndBlobsSidecarByRootRequest ): Promise; - lightClientBootstrap(peerId: PeerId, request: Uint8Array): Promise; - lightClientOptimisticUpdate(peerId: PeerId): Promise; - lightClientFinalityUpdate(peerId: PeerId): Promise; + lightClientBootstrap(peerId: PeerId, request: Uint8Array): Promise; + lightClientOptimisticUpdate(peerId: PeerId): Promise; + lightClientFinalityUpdate(peerId: PeerId): Promise; lightClientUpdatesByRange( peerId: PeerId, request: altair.LightClientUpdatesByRange - ): Promise; + ): Promise; } /** diff --git a/packages/light-client/src/events.ts b/packages/light-client/src/events.ts index 42d701a3e3ea..3bc500f461d1 100644 --- a/packages/light-client/src/events.ts +++ b/packages/light-client/src/events.ts @@ -1,4 +1,4 @@ -import {altair} from "@lodestar/types"; +import {allForks} from "@lodestar/types"; export enum LightclientEvent { lightClientOptimisticUpdate = "light_client_optimistic_update", @@ -6,8 +6,8 @@ export enum LightclientEvent { } export type LightclientEmitterEvents = { - [LightclientEvent.lightClientOptimisticUpdate]: (newHeader: altair.LightClientHeader) => void; - [LightclientEvent.lightClientFinalityUpdate]: (newHeader: altair.LightClientHeader) => void; + [LightclientEvent.lightClientOptimisticUpdate]: (newHeader: allForks.LightClientHeader) => void; + [LightclientEvent.lightClientFinalityUpdate]: (newHeader: allForks.LightClientHeader) => void; }; export type LightclientEmitter = MittEmitter; diff --git a/packages/light-client/src/index.ts b/packages/light-client/src/index.ts index e64ab517242d..295864c5bab2 100644 --- a/packages/light-client/src/index.ts +++ b/packages/light-client/src/index.ts @@ -1,7 +1,7 @@ import mitt from "mitt"; import {init as initBls} from "@chainsafe/bls/switchable"; import {EPOCHS_PER_SYNC_COMMITTEE_PERIOD} from "@lodestar/params"; -import {altair, phase0, RootHex, Slot, SyncPeriod} from "@lodestar/types"; +import {phase0, RootHex, Slot, SyncPeriod, allForks} from "@lodestar/types"; import {createIBeaconConfig, IBeaconConfig, IChainForkConfig} from "@lodestar/config"; import {isErrorAborted, sleep} from "@lodestar/utils"; import {fromHexString, toHexString} from "@chainsafe/ssz"; @@ -33,7 +33,7 @@ export type LightclientInitArgs = { opts?: LightclientOpts; genesisData: GenesisData; transport: LightClientTransport; - bootstrap: altair.LightClientBootstrap; + bootstrap: allForks.LightClientBootstrap; }; /** Provides some protection against a server client sending header updates too far away in the future */ @@ -172,7 +172,7 @@ export class Lightclient { this.status = {code: RunStatusCode.stopped}; } - getHead(): altair.LightClientHeader { + getHead(): allForks.LightClientHeader { return this.lightclientSpec.store.optimisticHeader; } @@ -286,7 +286,7 @@ export class Lightclient { * Processes new optimistic header updates in only known synced sync periods. * This headerUpdate may update the head if there's enough participation. */ - private processOptimisticUpdate(optimisticUpdate: altair.LightClientOptimisticUpdate): void { + private processOptimisticUpdate(optimisticUpdate: allForks.LightClientOptimisticUpdate): void { this.lightclientSpec.onOptimisticUpdate(this.currentSlotWithTolerance(), optimisticUpdate); } @@ -294,11 +294,11 @@ export class Lightclient { * Processes new header updates in only known synced sync periods. * This headerUpdate may update the head if there's enough participation. */ - private processFinalizedUpdate(finalizedUpdate: altair.LightClientFinalityUpdate): void { + private processFinalizedUpdate(finalizedUpdate: allForks.LightClientFinalityUpdate): void { this.lightclientSpec.onFinalityUpdate(this.currentSlotWithTolerance(), finalizedUpdate); } - private processSyncCommitteeUpdate(update: altair.LightClientUpdate): void { + private processSyncCommitteeUpdate(update: allForks.LightClientUpdate): void { this.lightclientSpec.onUpdate(this.currentSlotWithTolerance(), update); } diff --git a/packages/light-client/src/spec/index.ts b/packages/light-client/src/spec/index.ts index ea933665256f..9ecd1bc72de4 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -1,6 +1,6 @@ import {IBeaconConfig} from "@lodestar/config"; import {UPDATE_TIMEOUT} from "@lodestar/params"; -import {altair, Slot} from "@lodestar/types"; +import {Slot, allForks} from "@lodestar/types"; import {computeSyncPeriodAtSlot} from "../utils/index.js"; import {getSyncCommitteeAtPeriod, processLightClientUpdate, ProcessUpdateOpts} from "./processLightClientUpdate.js"; import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./store.js"; @@ -14,16 +14,16 @@ export class LightclientSpec { constructor( config: IBeaconConfig, private readonly opts: ProcessUpdateOpts & LightClientStoreEvents, - bootstrap: altair.LightClientBootstrap + bootstrap: allForks.LightClientBootstrap ) { this.store = new LightClientStore(config, bootstrap, opts); } - onUpdate(currentSlot: Slot, update: altair.LightClientUpdate): void { + onUpdate(currentSlot: Slot, update: allForks.LightClientUpdate): void { processLightClientUpdate(this.store, currentSlot, this.opts, update); } - onFinalityUpdate(currentSlot: Slot, finalityUpdate: altair.LightClientFinalityUpdate): void { + onFinalityUpdate(currentSlot: Slot, finalityUpdate: allForks.LightClientFinalityUpdate): void { this.onUpdate(currentSlot, { attestedHeader: finalityUpdate.attestedHeader, nextSyncCommittee: ZERO_SYNC_COMMITTEE, @@ -35,7 +35,7 @@ export class LightclientSpec { }); } - onOptimisticUpdate(currentSlot: Slot, optimisticUpdate: altair.LightClientOptimisticUpdate): void { + onOptimisticUpdate(currentSlot: Slot, optimisticUpdate: allForks.LightClientOptimisticUpdate): void { this.onUpdate(currentSlot, { attestedHeader: optimisticUpdate.attestedHeader, nextSyncCommittee: ZERO_SYNC_COMMITTEE, diff --git a/packages/light-client/src/spec/isBetterUpdate.ts b/packages/light-client/src/spec/isBetterUpdate.ts index a0f537327328..e149386cf97f 100644 --- a/packages/light-client/src/spec/isBetterUpdate.ts +++ b/packages/light-client/src/spec/isBetterUpdate.ts @@ -1,5 +1,5 @@ import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {altair, Slot} from "@lodestar/types"; +import {Slot, allForks} from "@lodestar/types"; import {computeSyncPeriodAtSlot} from "../utils/index.js"; import {isFinalityUpdate, isSyncCommitteeUpdate, sumBits} from "./utils.js"; @@ -82,7 +82,7 @@ export function isSafeLightClientUpdate(update: LightClientUpdateSummary): boole ); } -export function toLightClientUpdateSummary(update: altair.LightClientUpdate): LightClientUpdateSummary { +export function toLightClientUpdateSummary(update: allForks.LightClientUpdate): LightClientUpdateSummary { return { activeParticipants: sumBits(update.syncAggregate.syncCommitteeBits), attestedHeaderSlot: update.attestedHeader.beacon.slot, diff --git a/packages/light-client/src/spec/processLightClientUpdate.ts b/packages/light-client/src/spec/processLightClientUpdate.ts index 5ca212385a06..9ac0beb023ec 100644 --- a/packages/light-client/src/spec/processLightClientUpdate.ts +++ b/packages/light-client/src/spec/processLightClientUpdate.ts @@ -1,5 +1,5 @@ import {SYNC_COMMITTEE_SIZE} from "@lodestar/params"; -import {altair, Slot, SyncPeriod} from "@lodestar/types"; +import {Slot, SyncPeriod, allForks} from "@lodestar/types"; import {pruneSetToMax} from "@lodestar/utils"; import {computeSyncPeriodAtSlot, deserializeSyncCommittee, sumBits} from "../utils/index.js"; import {isBetterUpdate, LightClientUpdateSummary, toLightClientUpdateSummary} from "./isBetterUpdate.js"; @@ -16,7 +16,7 @@ export function processLightClientUpdate( store: ILightClientStore, currentSlot: Slot, opts: ProcessUpdateOpts, - update: altair.LightClientUpdate + update: allForks.LightClientUpdate ): void { if (update.signatureSlot > currentSlot) { throw Error(`update slot ${update.signatureSlot} must not be in the future, current slot ${currentSlot}`); diff --git a/packages/light-client/src/spec/store.ts b/packages/light-client/src/spec/store.ts index 36a35debd9fd..6cd88a485d87 100644 --- a/packages/light-client/src/spec/store.ts +++ b/packages/light-client/src/spec/store.ts @@ -1,6 +1,6 @@ import type {PublicKey} from "@chainsafe/bls/types"; import {IBeaconConfig} from "@lodestar/config"; -import {altair, SyncPeriod} from "@lodestar/types"; +import {SyncPeriod, allForks} from "@lodestar/types"; import {computeSyncPeriodAtSlot, deserializeSyncCommittee} from "../utils/index.js"; import {LightClientUpdateSummary} from "./isBetterUpdate.js"; @@ -18,29 +18,29 @@ export interface ILightClientStore { setActiveParticipants(period: SyncPeriod, activeParticipants: number): void; // Header that is finalized - finalizedHeader: altair.LightClientHeader; + finalizedHeader: allForks.LightClientHeader; // Most recent available reasonably-safe header - optimisticHeader: altair.LightClientHeader; + optimisticHeader: allForks.LightClientHeader; } export interface LightClientStoreEvents { - onSetFinalizedHeader?: (header: altair.LightClientHeader) => void; - onSetOptimisticHeader?: (header: altair.LightClientHeader) => void; + onSetFinalizedHeader?: (header: allForks.LightClientHeader) => void; + onSetOptimisticHeader?: (header: allForks.LightClientHeader) => void; } export class LightClientStore implements ILightClientStore { readonly syncCommittees = new Map(); readonly bestValidUpdates = new Map(); - private _finalizedHeader: altair.LightClientHeader; - private _optimisticHeader: altair.LightClientHeader; + private _finalizedHeader: allForks.LightClientHeader; + private _optimisticHeader: allForks.LightClientHeader; private readonly maxActiveParticipants = new Map(); constructor( readonly config: IBeaconConfig, - bootstrap: altair.LightClientBootstrap, + bootstrap: allForks.LightClientBootstrap, private readonly events: LightClientStoreEvents ) { const bootstrapPeriod = computeSyncPeriodAtSlot(bootstrap.header.beacon.slot); @@ -49,20 +49,20 @@ export class LightClientStore implements ILightClientStore { this._optimisticHeader = bootstrap.header; } - get finalizedHeader(): altair.LightClientHeader { + get finalizedHeader(): allForks.LightClientHeader { return this._finalizedHeader; } - set finalizedHeader(value: altair.LightClientHeader) { + set finalizedHeader(value: allForks.LightClientHeader) { this._finalizedHeader = value; this.events.onSetFinalizedHeader?.(value); } - get optimisticHeader(): altair.LightClientHeader { + get optimisticHeader(): allForks.LightClientHeader { return this._optimisticHeader; } - set optimisticHeader(value: altair.LightClientHeader) { + set optimisticHeader(value: allForks.LightClientHeader) { this._optimisticHeader = value; this.events.onSetOptimisticHeader?.(value); } @@ -95,7 +95,7 @@ export type SyncCommitteeFast = { }; export type LightClientUpdateWithSummary = { - update: altair.LightClientUpdate; + update: allForks.LightClientUpdate; summary: LightClientUpdateSummary; }; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index b9ec4a7ee7cf..e13ee7b5d2c2 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -1,6 +1,6 @@ import {BitArray, byteArrayEquals} from "@chainsafe/ssz"; import {FINALIZED_ROOT_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH} from "@lodestar/params"; -import {altair, phase0, ssz} from "@lodestar/types"; +import {altair, phase0, ssz, allForks} from "@lodestar/types"; export const GENESIS_SLOT = 0; export const ZERO_HASH = new Uint8Array(32); @@ -20,7 +20,7 @@ export function getSafetyThreshold(maxActiveParticipants: number): number { return Math.floor(maxActiveParticipants / SAFETY_THRESHOLD_FACTOR); } -export function isSyncCommitteeUpdate(update: altair.LightClientUpdate): boolean { +export function isSyncCommitteeUpdate(update: allForks.LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates update.nextSyncCommitteeBranch !== ZERO_NEXT_SYNC_COMMITTEE_BRANCH && @@ -28,7 +28,7 @@ export function isSyncCommitteeUpdate(update: altair.LightClientUpdate): boolean ); } -export function isFinalityUpdate(update: altair.LightClientUpdate): boolean { +export function isFinalityUpdate(update: allForks.LightClientUpdate): boolean { return ( // Fast return for when constructing full LightClientUpdate from partial updates update.finalityBranch !== ZERO_FINALITY_BRANCH && diff --git a/packages/light-client/src/spec/validateLightClientBootstrap.ts b/packages/light-client/src/spec/validateLightClientBootstrap.ts index af25b0414596..e1334d82800c 100644 --- a/packages/light-client/src/spec/validateLightClientBootstrap.ts +++ b/packages/light-client/src/spec/validateLightClientBootstrap.ts @@ -1,12 +1,12 @@ import {byteArrayEquals} from "@chainsafe/ssz"; -import {altair, Root, ssz} from "@lodestar/types"; +import {Root, ssz, allForks} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {isValidMerkleBranch} from "../utils/verifyMerkleBranch.js"; const CURRENT_SYNC_COMMITTEE_INDEX = 22; const CURRENT_SYNC_COMMITTEE_DEPTH = 5; -export function validateLightClientBootstrap(trustedBlockRoot: Root, bootstrap: altair.LightClientBootstrap): void { +export function validateLightClientBootstrap(trustedBlockRoot: Root, bootstrap: allForks.LightClientBootstrap): void { const headerRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(bootstrap.header.beacon); if (!byteArrayEquals(headerRoot, trustedBlockRoot)) { throw Error(`bootstrap header root ${toHex(headerRoot)} != trusted root ${toHex(trustedBlockRoot)}`); diff --git a/packages/light-client/src/spec/validateLightClientUpdate.ts b/packages/light-client/src/spec/validateLightClientUpdate.ts index cb45a9ca5550..1599d988fb38 100644 --- a/packages/light-client/src/spec/validateLightClientUpdate.ts +++ b/packages/light-client/src/spec/validateLightClientUpdate.ts @@ -1,4 +1,4 @@ -import {altair, Root, ssz} from "@lodestar/types"; +import {Root, ssz, allForks} from "@lodestar/types"; import bls from "@chainsafe/bls/switchable"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; import { @@ -18,7 +18,7 @@ import {ILightClientStore} from "./store.js"; export function validateLightClientUpdate( store: ILightClientStore, - update: altair.LightClientUpdate, + update: allForks.LightClientUpdate, syncCommittee: SyncCommitteeFast ): void { // Verify sync committee has sufficient participants diff --git a/packages/light-client/src/types.ts b/packages/light-client/src/types.ts index 21a4a5a926bb..6e6126f8a481 100644 --- a/packages/light-client/src/types.ts +++ b/packages/light-client/src/types.ts @@ -1,14 +1,14 @@ import type {PublicKey} from "@chainsafe/bls/types"; -import {altair, SyncPeriod} from "@lodestar/types"; +import {SyncPeriod, allForks} from "@lodestar/types"; export type LightClientStoreFast = { snapshot: LightClientSnapshotFast; - bestUpdates: Map; + bestUpdates: Map; }; export type LightClientSnapshotFast = { /** Beacon block header */ - header: altair.LightClientHeader; + header: allForks.LightClientHeader; /** Sync committees corresponding to the header */ currentSyncCommittee: SyncCommitteeFast; nextSyncCommittee: SyncCommitteeFast; diff --git a/packages/light-client/src/validation.ts b/packages/light-client/src/validation.ts index d42ab5e6c8ae..7b4c67392f5a 100644 --- a/packages/light-client/src/validation.ts +++ b/packages/light-client/src/validation.ts @@ -1,4 +1,4 @@ -import {altair, Root, Slot, ssz} from "@lodestar/types"; +import {altair, Root, Slot, ssz, allForks} from "@lodestar/types"; import bls from "@chainsafe/bls/switchable"; import type {PublicKey, Signature} from "@chainsafe/bls/types"; import { @@ -24,7 +24,7 @@ import {computeSyncPeriodAtSlot} from "./utils/clock.js"; export function assertValidLightClientUpdate( config: IBeaconConfig, syncCommittee: SyncCommitteeFast, - update: altair.LightClientUpdate + update: allForks.LightClientUpdate ): void { // DIFF FROM SPEC: An update with the same header.slot can be valid and valuable to the lightclient // It may have more consensus and result in a better snapshot whilst not advancing the state @@ -64,7 +64,7 @@ export function assertValidLightClientUpdate( * * Where `hashTreeRoot(state) == update.finalityHeader.stateRoot` */ -export function assertValidFinalityProof(update: altair.LightClientFinalityUpdate): void { +export function assertValidFinalityProof(update: allForks.LightClientFinalityUpdate): void { if ( !isValidMerkleBranch( ssz.phase0.BeaconBlockHeader.hashTreeRoot(update.finalizedHeader.beacon), @@ -94,7 +94,7 @@ export function assertValidFinalityProof(update: altair.LightClientFinalityUpdat * * Where `hashTreeRoot(state) == update.header.stateRoot` */ -export function assertValidSyncCommitteeProof(update: altair.LightClientUpdate): void { +export function assertValidSyncCommitteeProof(update: allForks.LightClientUpdate): void { if ( !isValidMerkleBranch( ssz.altair.SyncCommittee.hashTreeRoot(update.nextSyncCommittee), From a736d82639f92bd09db46890e76317ae5e0f99e3 Mon Sep 17 00:00:00 2001 From: gajinder Date: Mon, 6 Feb 2023 21:44:26 +0530 Subject: [PATCH 20/25] fix the update serialize/deserialize --- .../src/chain/lightClient/index.ts | 70 ++++++++++++------- .../db/repositories/lightclientBestUpdate.ts | 17 ++++- packages/beacon-node/src/util/multifork.ts | 27 +------ 3 files changed, 60 insertions(+), 54 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 9aa939ac17d9..adbf5e6a62fd 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -1,4 +1,4 @@ -import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod, allForks} from "@lodestar/types"; +import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod, allForks, capella} from "@lodestar/types"; import {IChainForkConfig} from "@lodestar/config"; import { CachedBeaconStateAltair, @@ -11,7 +11,14 @@ import {isBetterUpdate, toLightClientUpdateSummary, LightClientUpdateSummary} fr import {ILogger, MapDef, pruneSetToMax} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {BitArray, CompositeViewDU, toHexString} from "@chainsafe/ssz"; -import {MIN_SYNC_COMMITTEE_PARTICIPANTS, SYNC_COMMITTEE_SIZE, ForkName, ForkSeq, ForkExecution} from "@lodestar/params"; +import { + MIN_SYNC_COMMITTEE_PARTICIPANTS, + SYNC_COMMITTEE_SIZE, + ForkName, + ForkSeq, + ForkExecution, + isForkLightClient, +} from "@lodestar/params"; import {IBeaconDb} from "../../db/index.js"; import {IMetrics} from "../../metrics/index.js"; @@ -577,40 +584,44 @@ export class LightClientServer { throw Error("nextSyncCommittee not available"); } const nextSyncCommitteeBranch = getNextSyncCommitteeBranch(syncCommitteeWitness); - const finalizedHeader = attestedData.isFinalized + const finalizedHeaderAttested = attestedData.isFinalized ? await this.getFinalizedHeader(attestedData.finalizedCheckpoint.root as Uint8Array) : null; - let newUpdate: allForks.LightClientUpdate; - let isFinalized; + let isFinalized, finalityBranch, finalizedHeader; + if ( attestedData.isFinalized && - finalizedHeader && - computeSyncPeriodAtSlot(finalizedHeader.beacon.slot) == syncPeriod + finalizedHeaderAttested && + computeSyncPeriodAtSlot(finalizedHeaderAttested.beacon.slot) == syncPeriod ) { isFinalized = true; - newUpdate = { - attestedHeader, - nextSyncCommittee: nextSyncCommittee, - nextSyncCommitteeBranch, - finalizedHeader, - finalityBranch: attestedData.finalityBranch, - syncAggregate, - signatureSlot, - }; + finalityBranch = attestedData.finalityBranch; + finalizedHeader = finalizedHeaderAttested; } else { isFinalized = false; - newUpdate = { - attestedHeader, - nextSyncCommittee: nextSyncCommittee, - nextSyncCommitteeBranch, - finalizedHeader: this.zero.finalizedHeader, - finalityBranch: this.zero.finalityBranch, - syncAggregate, - signatureSlot, - }; + finalityBranch = this.zero.finalityBranch; + finalizedHeader = this.zero.finalizedHeader; + } + + // TODO capella: have a more graceful upgradtion condition and code + if ( + (attestedHeader as capella.LightClientHeader).execution !== undefined && + (finalizedHeader as capella.LightClientHeader).execution === undefined + ) { + finalizedHeader = upgradeLightClientHeader(this.config.getForkName(attestedHeader.beacon.slot), finalizedHeader); } + const newUpdate = { + attestedHeader, + nextSyncCommittee: nextSyncCommittee, + nextSyncCommitteeBranch, + finalizedHeader, + finalityBranch, + syncAggregate, + signatureSlot, + } as allForks.LightClientUpdate; + // attestedData and the block of syncAggregate may not be in same sync period // should not use attested data slot as sync period // see https://github.com/ChainSafe/lodestar/issues/3933 @@ -699,3 +710,12 @@ export function blockToLightClientHeader( return {beacon}; } } + +export function upgradeLightClientHeader(fork: ForkName, header: altair.LightClientHeader): allForks.LightClientHeader { + const upgradedHeader = (isForkLightClient(fork) + ? ssz.allForksLightClient[fork].LightClientHeader + : ssz.altair.LightClientHeader + ).defaultValue(); + upgradedHeader.beacon = header.beacon; + return upgradedHeader; +} diff --git a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts index 552f52960408..2595cfa7f89e 100644 --- a/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts +++ b/packages/beacon-node/src/db/repositories/lightclientBestUpdate.ts @@ -2,7 +2,7 @@ import {IChainForkConfig} from "@lodestar/config"; import {Bucket, IDatabaseController, Repository} from "@lodestar/db"; import {ssz, SyncPeriod, allForks} from "@lodestar/types"; -import {getLightClientUpdateTypeFromBytes} from "../../util/multifork.js"; +const SLOT_BYTE_COUNT = 8; /** * Best PartialLightClientUpdate in each SyncPeriod @@ -17,12 +17,23 @@ export class BestLightClientUpdateRepository extends Repository Date: Tue, 7 Feb 2023 11:50:23 +0530 Subject: [PATCH 21/25] fix error log --- packages/config/src/forkConfig/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 3937a0fc71d9..38d72d1c1d02 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -107,7 +107,7 @@ export function createIForkConfig(config: IChainConfig): IForkConfig { getLightClientForkTypes(slot: Slot): allForks.AllForksLightClientSSZTypes { const forkName = this.getForkName(slot); if (!isForkLightClient(forkName)) { - throw Error(`Invalid slot=${slot} fork=${forkName} for execution fork types`); + throw Error(`Invalid slot=${slot} fork=${forkName} for lightclient fork types`); } return ssz.allForksLightClient[forkName] as allForks.AllForksLightClientSSZTypes; }, From 1addcab62e8c43cebb8059e053e1f392ecc3c632 Mon Sep 17 00:00:00 2001 From: gajinder Date: Tue, 7 Feb 2023 17:55:52 +0530 Subject: [PATCH 22/25] better fork determination for update --- packages/beacon-node/src/chain/lightClient/index.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index adbf5e6a62fd..a2b52335b22d 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -1,4 +1,4 @@ -import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod, allForks, capella} from "@lodestar/types"; +import {altair, phase0, Root, RootHex, Slot, ssz, SyncPeriod, allForks} from "@lodestar/types"; import {IChainForkConfig} from "@lodestar/config"; import { CachedBeaconStateAltair, @@ -604,12 +604,9 @@ export class LightClientServer { finalizedHeader = this.zero.finalizedHeader; } - // TODO capella: have a more graceful upgradtion condition and code - if ( - (attestedHeader as capella.LightClientHeader).execution !== undefined && - (finalizedHeader as capella.LightClientHeader).execution === undefined - ) { - finalizedHeader = upgradeLightClientHeader(this.config.getForkName(attestedHeader.beacon.slot), finalizedHeader); + const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); + if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { + finalizedHeader = upgradeLightClientHeader(attestedFork, finalizedHeader); } const newUpdate = { @@ -711,6 +708,7 @@ export function blockToLightClientHeader( } } +// TODO: Correctly upgrade through multi fork, right now it effectively does pre capella -> capella fork export function upgradeLightClientHeader(fork: ForkName, header: altair.LightClientHeader): allForks.LightClientHeader { const upgradedHeader = (isForkLightClient(fork) ? ssz.allForksLightClient[fork].LightClientHeader From 92b44f33c0273f914bb8df30a7ab68dfdaa0a27b Mon Sep 17 00:00:00 2001 From: gajinder Date: Tue, 7 Feb 2023 18:03:06 +0530 Subject: [PATCH 23/25] fix the fork of finalized --- packages/beacon-node/src/chain/lightClient/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index a2b52335b22d..cc1398563c3c 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -504,7 +504,7 @@ export class LightClientServer { if (isFinalized) { const finalizedCheckpointRoot = attestedData.finalizedCheckpoint.root as Uint8Array; - const finalizedHeader = await this.getFinalizedHeader(finalizedCheckpointRoot); + let finalizedHeader = await this.getFinalizedHeader(finalizedCheckpointRoot); if ( finalizedHeader && @@ -512,6 +512,11 @@ export class LightClientServer { finalizedHeader.beacon.slot > this.finalized.finalizedHeader.beacon.slot || syncAggregateParticipation > sumBits(this.finalized.syncAggregate.syncCommitteeBits)) ) { + // Fork of LightClientFinalityUpdate is based off on attested header's fork + const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); + if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { + finalizedHeader = upgradeLightClientHeader(attestedFork, finalizedHeader); + } this.finalized = { attestedHeader, finalizedHeader, @@ -604,6 +609,7 @@ export class LightClientServer { finalizedHeader = this.zero.finalizedHeader; } + // Fork of LightClientUpdate is based off on attested header's fork const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { finalizedHeader = upgradeLightClientHeader(attestedFork, finalizedHeader); From e218dd3418bf4e7a826f7bf29012eb627ec69602 Mon Sep 17 00:00:00 2001 From: gajinder Date: Tue, 7 Feb 2023 19:15:17 +0530 Subject: [PATCH 24/25] fix tests --- .../test/e2e/network/gossipsub.test.ts | 14 ++++++------ .../lightClientFinalityUpdate.test.ts | 22 +++++++++++++------ .../lightClientOptimisticUpdate.test.ts | 22 ++++++++++--------- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/packages/beacon-node/test/e2e/network/gossipsub.test.ts b/packages/beacon-node/test/e2e/network/gossipsub.test.ts index e7f1ec2450d6..f9f21a1d1513 100644 --- a/packages/beacon-node/test/e2e/network/gossipsub.test.ts +++ b/packages/beacon-node/test/e2e/network/gossipsub.test.ts @@ -1,7 +1,7 @@ import sinon from "sinon"; import {expect} from "chai"; import {createIBeaconConfig, createIChainForkConfig, defaultChainConfig} from "@lodestar/config"; -import {capella, altair, phase0, ssz} from "@lodestar/types"; +import {capella, phase0, ssz, allForks} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; @@ -225,8 +225,8 @@ describe("gossipsub", function () { }); it("Publish and receive a LightClientOptimisticUpdate", async function () { - let onLightClientOptimisticUpdate: (ou: altair.LightClientOptimisticUpdate) => void; - const onLightClientOptimisticUpdatePromise = new Promise( + let onLightClientOptimisticUpdate: (ou: allForks.LightClientOptimisticUpdate) => void; + const onLightClientOptimisticUpdatePromise = new Promise( (resolve) => (onLightClientOptimisticUpdate = resolve) ); @@ -252,7 +252,7 @@ describe("gossipsub", function () { } } - const lightClientOptimisticUpdate = ssz.altair.LightClientOptimisticUpdate.defaultValue(); + const lightClientOptimisticUpdate = ssz.capella.LightClientOptimisticUpdate.defaultValue(); lightClientOptimisticUpdate.signatureSlot = START_SLOT; await netA.gossip.publishLightClientOptimisticUpdate(lightClientOptimisticUpdate); @@ -261,8 +261,8 @@ describe("gossipsub", function () { }); it("Publish and receive a LightClientFinalityUpdate", async function () { - let onLightClientFinalityUpdate: (fu: altair.LightClientFinalityUpdate) => void; - const onLightClientFinalityUpdatePromise = new Promise( + let onLightClientFinalityUpdate: (fu: allForks.LightClientFinalityUpdate) => void; + const onLightClientFinalityUpdatePromise = new Promise( (resolve) => (onLightClientFinalityUpdate = resolve) ); @@ -288,7 +288,7 @@ describe("gossipsub", function () { } } - const lightClientFinalityUpdate = ssz.altair.LightClientFinalityUpdate.defaultValue(); + const lightClientFinalityUpdate = ssz.capella.LightClientFinalityUpdate.defaultValue(); lightClientFinalityUpdate.signatureSlot = START_SLOT; await netA.gossip.publishLightClientFinalityUpdate(lightClientFinalityUpdate); diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts index 26e6eb004039..5aea7bad9e33 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts @@ -1,7 +1,6 @@ import {expect} from "chai"; import sinon from "sinon"; -import {createIBeaconConfig} from "@lodestar/config"; -import {config} from "@lodestar/config/default"; +import {createIBeaconConfig, createIChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {altair, ssz} from "@lodestar/types"; import {computeTimeAtSlot} from "@lodestar/state-transition"; @@ -14,6 +13,14 @@ import {IBeaconChain} from "../../../../src/chain/index.js"; describe("Light Client Finality Update validation", function () { let fakeClock: sinon.SinonFakeTimers; const afterEachCallbacks: (() => Promise | void)[] = []; + const config = createIChainForkConfig({ + ...defaultChainConfig, + /* eslint-disable @typescript-eslint/naming-convention */ + ALTAIR_FORK_EPOCH: 1, + BELLATRIX_FORK_EPOCH: 3, + CAPELLA_FORK_EPOCH: Infinity, + }); + beforeEach(() => { fakeClock = sinon.useFakeTimers(); }); @@ -93,15 +100,15 @@ describe("Light Client Finality Update validation", function () { it("should return invalid - finality update not matching local", async () => { const lightClientFinalityUpdate: altair.LightClientFinalityUpdate = ssz.altair.LightClientFinalityUpdate.defaultValue(); - lightClientFinalityUpdate.finalizedHeader.beacon.slot = 2; - lightClientFinalityUpdate.signatureSlot = lightClientFinalityUpdate.finalizedHeader.beacon.slot + 1; + lightClientFinalityUpdate.finalizedHeader.beacon.slot = 42; + lightClientFinalityUpdate.attestedHeader.beacon.slot = lightClientFinalityUpdate.finalizedHeader.beacon.slot + 1; const chain = mockChain(); // make lightclientserver return another update with different value from gossiped chain.lightClientServer.getFinalityUpdate = () => { const defaultValue = ssz.altair.LightClientFinalityUpdate.defaultValue(); - defaultValue.finalizedHeader.beacon.slot = 1; + defaultValue.finalizedHeader.beacon.slot = 41; return defaultValue; }; @@ -120,8 +127,8 @@ describe("Light Client Finality Update validation", function () { it("should return invalid - not matching local when no local finality update yet", async () => { const lightClientFinalityUpdate: altair.LightClientFinalityUpdate = ssz.altair.LightClientFinalityUpdate.defaultValue(); - lightClientFinalityUpdate.finalizedHeader.beacon.slot = 2; - lightClientFinalityUpdate.signatureSlot = lightClientFinalityUpdate.finalizedHeader.beacon.slot + 1; + lightClientFinalityUpdate.finalizedHeader.beacon.slot = 42; + lightClientFinalityUpdate.attestedHeader.beacon.slot = lightClientFinalityUpdate.finalizedHeader.beacon.slot + 1; const chain = mockChain(); @@ -149,6 +156,7 @@ describe("Light Client Finality Update validation", function () { // satisfy: // No other finality_update with a lower or equal finalized_header.beacon.slot was already forwarded on the network lightClientFinalityUpdate.finalizedHeader.beacon.slot = 2; + lightClientFinalityUpdate.signatureSlot = lightClientFinalityUpdate.finalizedHeader.beacon.slot + 1; chain.lightClientServer.getFinalityUpdate = () => { const defaultValue = ssz.altair.LightClientFinalityUpdate.defaultValue(); diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts index a5d2bfb1d7cc..71c941af1013 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts @@ -1,7 +1,6 @@ import {expect} from "chai"; import sinon from "sinon"; -import {createIBeaconConfig} from "@lodestar/config"; -import {config} from "@lodestar/config/default"; +import {createIBeaconConfig, createIChainForkConfig, defaultChainConfig} from "@lodestar/config"; import {altair, ssz} from "@lodestar/types"; import {computeTimeAtSlot} from "@lodestar/state-transition"; @@ -14,6 +13,15 @@ import {IBeaconChain} from "../../../../src/chain/index.js"; describe("Light Client Optimistic Update validation", function () { let fakeClock: sinon.SinonFakeTimers; const afterEachCallbacks: (() => Promise | void)[] = []; + // eslint-disable-next-line @typescript-eslint/naming-convention + const config = createIChainForkConfig({ + ...defaultChainConfig, + /* eslint-disable @typescript-eslint/naming-convention */ + ALTAIR_FORK_EPOCH: 1, + BELLATRIX_FORK_EPOCH: 3, + CAPELLA_FORK_EPOCH: Infinity, + }); + beforeEach(() => { fakeClock = sinon.useFakeTimers(); }); @@ -93,7 +101,7 @@ describe("Light Client Optimistic Update validation", function () { it("should return invalid - optimistic update not matching local", async () => { const lightclientOptimisticUpdate: altair.LightClientOptimisticUpdate = ssz.altair.LightClientOptimisticUpdate.defaultValue(); - lightclientOptimisticUpdate.attestedHeader.beacon.slot = 2; + lightclientOptimisticUpdate.attestedHeader.beacon.slot = 42; const chain = mockChain(); @@ -118,7 +126,7 @@ describe("Light Client Optimistic Update validation", function () { it("should return invalid - not matching local when no local optimistic update yet", async () => { const lightclientOptimisticUpdate: altair.LightClientOptimisticUpdate = ssz.altair.LightClientOptimisticUpdate.defaultValue(); - lightclientOptimisticUpdate.attestedHeader.beacon.slot = 2; + lightclientOptimisticUpdate.attestedHeader.beacon.slot = 42; const chain = mockChain(); @@ -145,12 +153,6 @@ describe("Light Client Optimistic Update validation", function () { // No other optimistic_update with a lower or equal attested_header.beacon.slot was already forwarded on the network lightclientOptimisticUpdate.attestedHeader.beacon.slot = 2; - chain.lightClientServer.getOptimisticUpdate = () => { - const defaultValue = ssz.altair.LightClientOptimisticUpdate.defaultValue(); - defaultValue.attestedHeader.beacon.slot = 1; - return defaultValue; - }; - // satisfy: // [IGNORE] The optimistic_update is received after the block at signature_slot was given enough time to propagate // through the network -- i.e. validate that one-third of optimistic_update.signature_slot has transpired From 7c4b52b9d2ed1467432309e34831aceaad145cc5 Mon Sep 17 00:00:00 2001 From: gajinder Date: Wed, 8 Feb 2023 14:55:37 +0530 Subject: [PATCH 25/25] fix header upgradation --- .../src/chain/lightClient/index.ts | 30 ++++---------- packages/light-client/src/spec/index.ts | 1 + packages/light-client/src/spec/utils.ts | 41 ++++++++++++++++++- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index cc1398563c3c..67ac63f8ca3e 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -7,18 +7,16 @@ import { computeSyncPeriodAtSlot, executionPayloadToPayloadHeader, } from "@lodestar/state-transition"; -import {isBetterUpdate, toLightClientUpdateSummary, LightClientUpdateSummary} from "@lodestar/light-client/spec"; +import { + isBetterUpdate, + toLightClientUpdateSummary, + LightClientUpdateSummary, + upgradeLightClientHeader, +} from "@lodestar/light-client/spec"; import {ILogger, MapDef, pruneSetToMax} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {BitArray, CompositeViewDU, toHexString} from "@chainsafe/ssz"; -import { - MIN_SYNC_COMMITTEE_PARTICIPANTS, - SYNC_COMMITTEE_SIZE, - ForkName, - ForkSeq, - ForkExecution, - isForkLightClient, -} from "@lodestar/params"; +import {MIN_SYNC_COMMITTEE_PARTICIPANTS, SYNC_COMMITTEE_SIZE, ForkName, ForkSeq, ForkExecution} from "@lodestar/params"; import {IBeaconDb} from "../../db/index.js"; import {IMetrics} from "../../metrics/index.js"; @@ -515,7 +513,7 @@ export class LightClientServer { // Fork of LightClientFinalityUpdate is based off on attested header's fork const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { - finalizedHeader = upgradeLightClientHeader(attestedFork, finalizedHeader); + finalizedHeader = upgradeLightClientHeader(this.config, attestedFork, finalizedHeader); } this.finalized = { attestedHeader, @@ -612,7 +610,7 @@ export class LightClientServer { // Fork of LightClientUpdate is based off on attested header's fork const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { - finalizedHeader = upgradeLightClientHeader(attestedFork, finalizedHeader); + finalizedHeader = upgradeLightClientHeader(this.config, attestedFork, finalizedHeader); } const newUpdate = { @@ -713,13 +711,3 @@ export function blockToLightClientHeader( return {beacon}; } } - -// TODO: Correctly upgrade through multi fork, right now it effectively does pre capella -> capella fork -export function upgradeLightClientHeader(fork: ForkName, header: altair.LightClientHeader): allForks.LightClientHeader { - const upgradedHeader = (isForkLightClient(fork) - ? ssz.allForksLightClient[fork].LightClientHeader - : ssz.altair.LightClientHeader - ).defaultValue(); - upgradedHeader.beacon = header.beacon; - return upgradedHeader; -} diff --git a/packages/light-client/src/spec/index.ts b/packages/light-client/src/spec/index.ts index 9ecd1bc72de4..9123101f5bfc 100644 --- a/packages/light-client/src/spec/index.ts +++ b/packages/light-client/src/spec/index.ts @@ -7,6 +7,7 @@ import {ILightClientStore, LightClientStore, LightClientStoreEvents} from "./sto import {ZERO_FINALITY_BRANCH, ZERO_HEADER, ZERO_NEXT_SYNC_COMMITTEE_BRANCH, ZERO_SYNC_COMMITTEE} from "./utils.js"; export {isBetterUpdate, toLightClientUpdateSummary, LightClientUpdateSummary} from "./isBetterUpdate.js"; +export {upgradeLightClientHeader} from "./utils.js"; export class LightclientSpec { readonly store: ILightClientStore; diff --git a/packages/light-client/src/spec/utils.ts b/packages/light-client/src/spec/utils.ts index e13ee7b5d2c2..04c17b7edc0a 100644 --- a/packages/light-client/src/spec/utils.ts +++ b/packages/light-client/src/spec/utils.ts @@ -1,6 +1,7 @@ import {BitArray, byteArrayEquals} from "@chainsafe/ssz"; -import {FINALIZED_ROOT_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH} from "@lodestar/params"; -import {altair, phase0, ssz, allForks} from "@lodestar/types"; +import {FINALIZED_ROOT_DEPTH, NEXT_SYNC_COMMITTEE_DEPTH, ForkSeq, ForkName} from "@lodestar/params"; +import {altair, phase0, ssz, allForks, capella, deneb} from "@lodestar/types"; +import {IChainForkConfig} from "@lodestar/config"; export const GENESIS_SLOT = 0; export const ZERO_HASH = new Uint8Array(32); @@ -45,3 +46,39 @@ export function isZeroedSyncCommittee(syncCommittee: altair.SyncCommittee): bool // Fast return for when constructing full LightClientUpdate from partial updates return syncCommittee === ZERO_SYNC_COMMITTEE || byteArrayEquals(syncCommittee.pubkeys[0], ZERO_PUBKEY); } + +export function upgradeLightClientHeader( + config: IChainForkConfig, + targetFork: ForkName, + header: altair.LightClientHeader +): allForks.LightClientHeader { + const upgradedHeader = header; + + const headerFork = config.getForkName(header.beacon.slot); + switch (headerFork) { + case ForkName.phase0: + throw Error(`Invalid target fork=${headerFork} for LightClientHeader`); + + case ForkName.altair: + case ForkName.bellatrix: + // Break if no further upgradation is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.bellatrix) break; + // eslint-disable-next-line no-fallthrough + + case ForkName.capella: + (upgradedHeader as capella.LightClientHeader).execution = ssz.capella.LightClientHeader.fields.execution.defaultValue(); + (upgradedHeader as capella.LightClientHeader).executionBranch = ssz.capella.LightClientHeader.fields.executionBranch.defaultValue(); + + // Break if no further upgradation is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.capella) break; + // eslint-disable-next-line no-fallthrough + + case ForkName.deneb: + (upgradedHeader as deneb.LightClientHeader).execution.excessDataGas = ssz.deneb.LightClientHeader.fields.execution.fields.excessDataGas.defaultValue(); + + // Break if no further upgradation is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.deneb) break; + // eslint-disable-next-line no-fallthrough + } + return upgradedHeader; +}