1
1
import { BitArray , CompositeViewDU } from "@chainsafe/ssz" ;
2
+ import { routes } from "@lodestar/api" ;
3
+ import { ChainForkConfig } from "@lodestar/config" ;
4
+ import {
5
+ LightClientUpdateSummary ,
6
+ isBetterUpdate ,
7
+ toLightClientUpdateSummary ,
8
+ upgradeLightClientHeader ,
9
+ } from "@lodestar/light-client/spec" ;
10
+ import {
11
+ ForkExecution ,
12
+ ForkLightClient ,
13
+ ForkName ,
14
+ ForkSeq ,
15
+ MIN_SYNC_COMMITTEE_PARTICIPANTS ,
16
+ SYNC_COMMITTEE_SIZE ,
17
+ forkLightClient ,
18
+ highestFork ,
19
+ isForkPostElectra ,
20
+ } from "@lodestar/params" ;
21
+ import {
22
+ CachedBeaconStateAltair ,
23
+ computeStartSlotAtEpoch ,
24
+ computeSyncPeriodAtEpoch ,
25
+ computeSyncPeriodAtSlot ,
26
+ executionPayloadToPayloadHeader ,
27
+ } from "@lodestar/state-transition" ;
2
28
import {
3
- altair ,
4
29
BeaconBlock ,
5
30
BeaconBlockBody ,
6
31
LightClientBootstrap ,
7
32
LightClientFinalityUpdate ,
8
33
LightClientHeader ,
9
34
LightClientOptimisticUpdate ,
10
35
LightClientUpdate ,
11
- phase0 ,
12
36
Root ,
13
37
RootHex ,
38
+ SSZTypesFor ,
14
39
Slot ,
40
+ SyncPeriod ,
41
+ altair ,
42
+ electra ,
43
+ phase0 ,
15
44
ssz ,
16
45
sszTypesFor ,
17
- SSZTypesFor ,
18
- SyncPeriod ,
19
46
} from "@lodestar/types" ;
20
- import { ChainForkConfig } from "@lodestar/config" ;
21
- import {
22
- CachedBeaconStateAltair ,
23
- computeStartSlotAtEpoch ,
24
- computeSyncPeriodAtEpoch ,
25
- computeSyncPeriodAtSlot ,
26
- executionPayloadToPayloadHeader ,
27
- } from "@lodestar/state-transition" ;
28
- import {
29
- isBetterUpdate ,
30
- toLightClientUpdateSummary ,
31
- LightClientUpdateSummary ,
32
- upgradeLightClientHeader ,
33
- } from "@lodestar/light-client/spec" ;
34
47
import { Logger , MapDef , pruneSetToMax , toRootHex } from "@lodestar/utils" ;
35
- import { routes } from "@lodestar/api" ;
36
- import {
37
- MIN_SYNC_COMMITTEE_PARTICIPANTS ,
38
- SYNC_COMMITTEE_SIZE ,
39
- ForkName ,
40
- ForkSeq ,
41
- ForkExecution ,
42
- ForkLightClient ,
43
- highestFork ,
44
- forkLightClient ,
45
- } from "@lodestar/params" ;
46
48
49
+ import { ZERO_HASH } from "../../constants/index.js" ;
47
50
import { IBeaconDb } from "../../db/index.js" ;
51
+ import { NUM_WITNESS , NUM_WITNESS_ELECTRA } from "../../db/repositories/lightclientSyncCommitteeWitness.js" ;
48
52
import { Metrics } from "../../metrics/index.js" ;
49
- import { ChainEventEmitter } from "../emitter.js" ;
50
53
import { byteArrayEquals } from "../../util/bytes.js" ;
51
- import { ZERO_HASH } from "../../constants/index .js" ;
54
+ import { ChainEventEmitter } from "../emitter .js" ;
52
55
import { LightClientServerError , LightClientServerErrorCode } from "../errors/lightClientError.js" ;
53
56
import {
57
+ getBlockBodyExecutionHeaderProof ,
58
+ getCurrentSyncCommitteeBranch ,
59
+ getFinalizedRootProof ,
54
60
getNextSyncCommitteeBranch ,
55
61
getSyncCommitteesWitness ,
56
- getFinalizedRootProof ,
57
- getCurrentSyncCommitteeBranch ,
58
- getBlockBodyExecutionHeaderProof ,
59
62
} from "./proofs.js" ;
60
63
61
64
export type LightClientServerOpts = {
@@ -208,7 +211,10 @@ export class LightClientServer {
208
211
private checkpointHeaders = new Map < BlockRooHex , LightClientHeader > ( ) ;
209
212
private latestHeadUpdate : LightClientOptimisticUpdate | null = null ;
210
213
211
- private readonly zero : Pick < altair . LightClientUpdate , "finalityBranch" | "finalizedHeader" > ;
214
+ private readonly zero : Pick <
215
+ altair . LightClientUpdate | electra . LightClientUpdate ,
216
+ "finalityBranch" | "finalizedHeader"
217
+ > ;
212
218
private finalized : LightClientFinalityUpdate | null = null ;
213
219
214
220
constructor (
@@ -225,7 +231,9 @@ export class LightClientServer {
225
231
this . zero = {
226
232
// Assign the hightest fork's default value because it can always be typecasted down to correct fork
227
233
finalizedHeader : sszTypesFor ( highestFork ( forkLightClient ) ) . LightClientHeader . defaultValue ( ) ,
228
- finalityBranch : ssz . altair . LightClientUpdate . fields . finalityBranch . defaultValue ( ) ,
234
+ // Electra finalityBranch has fixed length of 5 whereas altair has 4. The fifth element will be ignored
235
+ // when serializing as altair LightClientUpdate
236
+ finalityBranch : ssz . electra . LightClientUpdate . fields . finalityBranch . defaultValue ( ) ,
229
237
} ;
230
238
231
239
if ( metrics ) {
@@ -388,12 +396,13 @@ export class LightClientServer {
388
396
parentBlockSlot : Slot
389
397
) : Promise < void > {
390
398
const blockSlot = block . slot ;
391
- const header = blockToLightClientHeader ( this . config . getForkName ( blockSlot ) , block ) ;
399
+ const fork = this . config . getForkName ( blockSlot ) ;
400
+ const header = blockToLightClientHeader ( fork , block ) ;
392
401
393
402
const blockRoot = ssz . phase0 . BeaconBlockHeader . hashTreeRoot ( header . beacon ) ;
394
403
const blockRootHex = toRootHex ( blockRoot ) ;
395
404
396
- const syncCommitteeWitness = getSyncCommitteesWitness ( postState ) ;
405
+ const syncCommitteeWitness = getSyncCommitteesWitness ( fork , postState ) ;
397
406
398
407
// Only store current sync committee once per run
399
408
if ( ! this . storedCurrentSyncCommittee ) {
@@ -621,6 +630,16 @@ export class LightClientServer {
621
630
if ( ! syncCommitteeWitness ) {
622
631
throw Error ( `syncCommitteeWitness not available at ${ toRootHex ( attestedData . blockRoot ) } ` ) ;
623
632
}
633
+
634
+ const attestedFork = this . config . getForkName ( attestedHeader . beacon . slot ) ;
635
+ const numWitness = syncCommitteeWitness . witness . length ;
636
+ if ( isForkPostElectra ( attestedFork ) && numWitness !== NUM_WITNESS_ELECTRA ) {
637
+ throw Error ( `Expected ${ NUM_WITNESS_ELECTRA } witnesses in post-Electra numWitness=${ numWitness } ` ) ;
638
+ }
639
+ if ( ! isForkPostElectra ( attestedFork ) && numWitness !== NUM_WITNESS ) {
640
+ throw Error ( `Expected ${ NUM_WITNESS } witnesses in pre-Electra numWitness=${ numWitness } ` ) ;
641
+ }
642
+
624
643
const nextSyncCommittee = await this . db . syncCommittee . get ( syncCommitteeWitness . nextSyncCommitteeRoot ) ;
625
644
if ( ! nextSyncCommittee ) {
626
645
throw Error ( "nextSyncCommittee not available" ) ;
@@ -641,7 +660,6 @@ export class LightClientServer {
641
660
finalityBranch = attestedData . finalityBranch ;
642
661
finalizedHeader = finalizedHeaderAttested ;
643
662
// Fork of LightClientUpdate is based off on attested header's fork
644
- const attestedFork = this . config . getForkName ( attestedHeader . beacon . slot ) ;
645
663
if ( this . config . getForkName ( finalizedHeader . beacon . slot ) !== attestedFork ) {
646
664
finalizedHeader = upgradeLightClientHeader ( this . config , attestedFork , finalizedHeader ) ;
647
665
}
0 commit comments