@@ -2,7 +2,17 @@ import {CoordType, PublicKey} from "@chainsafe/bls/types";
2
2
import bls from "@chainsafe/bls" ;
3
3
import * as immutable from "immutable" ;
4
4
import { fromHexString } from "@chainsafe/ssz" ;
5
- import { BLSSignature , CommitteeIndex , Epoch , Slot , ValidatorIndex , phase0 , SyncPeriod } from "@lodestar/types" ;
5
+ import {
6
+ BLSSignature ,
7
+ CommitteeIndex ,
8
+ Epoch ,
9
+ Slot ,
10
+ ValidatorIndex ,
11
+ phase0 ,
12
+ SyncPeriod ,
13
+ allForks ,
14
+ electra ,
15
+ } from "@lodestar/types" ;
6
16
import { createBeaconConfig , BeaconConfig , ChainConfig } from "@lodestar/config" ;
7
17
import {
8
18
ATTESTATION_SUBNET_COUNT ,
@@ -645,15 +655,47 @@ export class EpochCache {
645
655
* Return the beacon committee at slot for index.
646
656
*/
647
657
getBeaconCommittee ( slot : Slot , index : CommitteeIndex ) : Uint32Array {
658
+ return this . getBeaconCommittees ( slot , [ index ] ) ;
659
+ }
660
+
661
+ /**
662
+ * Return a single Uint32Array representing concatted committees of indices
663
+ */
664
+ getBeaconCommittees ( slot : Slot , indices : CommitteeIndex [ ] ) : Uint32Array {
665
+ if ( indices . length === 0 ) {
666
+ throw new Error ( "Attempt to get committees without providing CommitteeIndex" ) ;
667
+ }
668
+
648
669
const slotCommittees = this . getShufflingAtSlot ( slot ) . committees [ slot % SLOTS_PER_EPOCH ] ;
649
- if ( index >= slotCommittees . length ) {
650
- throw new EpochCacheError ( {
651
- code : EpochCacheErrorCode . COMMITTEE_INDEX_OUT_OF_RANGE ,
652
- index,
653
- maxIndex : slotCommittees . length ,
654
- } ) ;
670
+ const committees = [ ] ;
671
+
672
+ for ( const index of indices ) {
673
+ if ( index >= slotCommittees . length ) {
674
+ throw new EpochCacheError ( {
675
+ code : EpochCacheErrorCode . COMMITTEE_INDEX_OUT_OF_RANGE ,
676
+ index,
677
+ maxIndex : slotCommittees . length ,
678
+ } ) ;
679
+ }
680
+ committees . push ( slotCommittees [ index ] ) ;
681
+ }
682
+
683
+ // Early return if only one index
684
+ if ( committees . length === 1 ) {
685
+ return committees [ 0 ] ;
686
+ }
687
+
688
+ // Create a new Uint32Array to flatten `committees`
689
+ const totalLength = committees . reduce ( ( acc , curr ) => acc + curr . length , 0 ) ;
690
+ const result = new Uint32Array ( totalLength ) ;
691
+
692
+ let offset = 0 ;
693
+ for ( const committee of committees ) {
694
+ result . set ( committee , offset ) ;
695
+ offset += committee . length ;
655
696
}
656
- return slotCommittees [ index ] ;
697
+
698
+ return result ;
657
699
}
658
700
659
701
getCommitteeCountPerSlot ( epoch : Epoch ) : number {
@@ -739,10 +781,9 @@ export class EpochCache {
739
781
/**
740
782
* Return the indexed attestation corresponding to ``attestation``.
741
783
*/
742
- getIndexedAttestation ( attestation : phase0 . Attestation ) : phase0 . IndexedAttestation {
743
- const { aggregationBits, data} = attestation ;
744
- const committeeIndices = this . getBeaconCommittee ( data . slot , data . index ) ;
745
- const attestingIndices = aggregationBits . intersectValues ( committeeIndices ) ;
784
+ getIndexedAttestation ( fork : ForkSeq , attestation : allForks . Attestation ) : allForks . IndexedAttestation {
785
+ const { data} = attestation ;
786
+ const attestingIndices = this . getAttestingIndices ( fork , attestation ) ;
746
787
747
788
// sort in-place
748
789
attestingIndices . sort ( ( a , b ) => a - b ) ;
@@ -753,6 +794,31 @@ export class EpochCache {
753
794
} ;
754
795
}
755
796
797
+ /**
798
+ * Return indices of validators who attestested in `attestation`
799
+ */
800
+ getAttestingIndices ( fork : ForkSeq , attestation : allForks . Attestation ) : number [ ] {
801
+ if ( fork < ForkSeq . electra ) {
802
+ const { aggregationBits, data} = attestation ;
803
+ const validatorIndices = this . getBeaconCommittee ( data . slot , data . index ) ;
804
+
805
+ return aggregationBits . intersectValues ( validatorIndices ) ;
806
+ } else {
807
+ const { aggregationBits, committeeBits, data} = attestation as electra . Attestation ;
808
+
809
+ // There is a naming conflict on the term `committeeIndices`
810
+ // In Lodestar it usually means a list of validator indices of participants in a committee
811
+ // In the spec it means a list of committee indices according to committeeBits
812
+ // This `committeeIndices` refers to the latter
813
+ // TODO Electra: resolve the naming conflicts
814
+ const committeeIndices = committeeBits . getTrueBitIndexes ( ) ;
815
+
816
+ const validatorIndices = this . getBeaconCommittees ( data . slot , committeeIndices ) ;
817
+
818
+ return aggregationBits . intersectValues ( validatorIndices ) ;
819
+ }
820
+ }
821
+
756
822
getCommitteeAssignments (
757
823
epoch : Epoch ,
758
824
requestedValidatorIndices : ValidatorIndex [ ]
0 commit comments