@@ -4,13 +4,15 @@ import {createChainForkConfig, defaultChainConfig} from "@lodestar/config";
4
4
import {
5
5
FAR_FUTURE_EPOCH ,
6
6
ForkName ,
7
+ ForkPostElectra ,
7
8
MAX_COMMITTEES_PER_SLOT ,
8
9
MAX_EFFECTIVE_BALANCE ,
10
+ MAX_VALIDATORS_PER_COMMITTEE ,
9
11
SLOTS_PER_EPOCH ,
10
12
} from "@lodestar/params" ;
11
- import { CachedBeaconStateAllForks , newFilledArray } from "@lodestar/state-transition" ;
13
+ import { CachedBeaconStateAllForks , CachedBeaconStateElectra , newFilledArray } from "@lodestar/state-transition" ;
12
14
import { CachedBeaconStateAltair } from "@lodestar/state-transition/src/types.js" ;
13
- import { phase0 , ssz } from "@lodestar/types" ;
15
+ import { Attestation , phase0 , ssz } from "@lodestar/types" ;
14
16
import { afterEach , beforeAll , beforeEach , describe , expect , it , vi } from "vitest" ;
15
17
import {
16
18
AggregatedAttestationPool ,
@@ -25,7 +27,7 @@ import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js";
25
27
import { linspace } from "../../../../src/util/numpy.js" ;
26
28
import { MockedForkChoice , getMockedForkChoice } from "../../../mocks/mockedBeaconChain.js" ;
27
29
import { renderBitArray } from "../../../utils/render.js" ;
28
- import { generateCachedAltairState } from "../../../utils/state.js" ;
30
+ import { generateCachedAltairState , generateCachedElectraState } from "../../../utils/state.js" ;
29
31
import { generateProtoBlock } from "../../../utils/typeGenerator.js" ;
30
32
import { generateValidators } from "../../../utils/validator.js" ;
31
33
@@ -34,7 +36,7 @@ const validSignature = fromHexString(
34
36
"0xb2afb700f6c561ce5e1b4fedaec9d7c06b822d38c720cf588adfda748860a940adf51634b6788f298c552de40183b5a203b2bbe8b7dd147f0bb5bc97080a12efbb631c8888cb31a99cc4706eb3711865b8ea818c10126e4d818b542e9dbf9ae8"
35
37
) ;
36
38
37
- describe ( "AggregatedAttestationPool" , ( ) => {
39
+ describe ( "AggregatedAttestationPool - Altair " , ( ) => {
38
40
let pool : AggregatedAttestationPool ;
39
41
const fork = ForkName . altair ;
40
42
const config = createChainForkConfig ( {
@@ -158,6 +160,143 @@ describe("AggregatedAttestationPool", () => {
158
160
} ) ;
159
161
} ) ;
160
162
163
+ describe ( "AggregatedAttestationPool - Electra" , ( ) => {
164
+ let pool : AggregatedAttestationPool ;
165
+ const fork = ForkName . electra ;
166
+ const electraForkEpoch = 2020 ;
167
+ const config = createChainForkConfig ( {
168
+ ...defaultChainConfig ,
169
+ ALTAIR_FORK_EPOCH : 0 ,
170
+ BELLATRIX_FORK_EPOCH : 0 ,
171
+ CAPELLA_FORK_EPOCH : 0 ,
172
+ DENEB_FORK_EPOCH : 0 ,
173
+ ELECTRA_FORK_EPOCH : electraForkEpoch ,
174
+ } ) ;
175
+ const currentEpoch = electraForkEpoch + 10 ;
176
+ const currentSlot = SLOTS_PER_EPOCH * currentEpoch ;
177
+
178
+ const committeeIndices = [ 0 , 1 , 2 , 3 ] ;
179
+ const attestation = ssz . electra . Attestation . defaultValue ( ) ;
180
+ attestation . data . slot = currentSlot ;
181
+ attestation . data . index = 0 ; // Must be zero post-electra
182
+ attestation . data . target . epoch = currentEpoch ;
183
+ attestation . signature = validSignature ;
184
+ const attDataRootHex = toHexString ( ssz . phase0 . AttestationData . hashTreeRoot ( attestation . data ) ) ;
185
+
186
+ const validatorOpts = {
187
+ activationEpoch : 0 ,
188
+ effectiveBalance : MAX_EFFECTIVE_BALANCE ,
189
+ withdrawableEpoch : FAR_FUTURE_EPOCH ,
190
+ exitEpoch : FAR_FUTURE_EPOCH ,
191
+ } ;
192
+ // this makes a committee length of 4
193
+ const vc = 1024 ;
194
+ const committeeLength = 32 ;
195
+ const validators = generateValidators ( vc , validatorOpts ) ;
196
+ const originalState = generateCachedElectraState ( { slot : currentSlot + 1 , validators} , electraForkEpoch ) ;
197
+ expect ( originalState . epochCtx . getCommitteeCountPerSlot ( currentEpoch ) ) . toEqual ( committeeIndices . length ) ;
198
+
199
+ const committees = originalState . epochCtx . getBeaconCommittees ( currentSlot , committeeIndices ) ;
200
+
201
+ const epochParticipation = newFilledArray ( vc , 0b000 ) ;
202
+ for ( const committee of committees ) {
203
+ expect ( committee . length ) . toEqual ( committeeLength ) ;
204
+ }
205
+
206
+ ( originalState as CachedBeaconStateElectra ) . previousEpochParticipation =
207
+ ssz . altair . EpochParticipation . toViewDU ( epochParticipation ) ;
208
+ ( originalState as CachedBeaconStateElectra ) . currentEpochParticipation =
209
+ ssz . altair . EpochParticipation . toViewDU ( epochParticipation ) ;
210
+ originalState . commit ( ) ;
211
+ let electraState : CachedBeaconStateAllForks ;
212
+
213
+ let forkchoiceStub : MockedForkChoice ;
214
+
215
+ beforeEach ( ( ) => {
216
+ pool = new AggregatedAttestationPool ( config ) ;
217
+ electraState = originalState . clone ( ) ;
218
+ forkchoiceStub = getMockedForkChoice ( ) ;
219
+ } ) ;
220
+
221
+ afterEach ( ( ) => {
222
+ vi . clearAllMocks ( ) ;
223
+ } ) ;
224
+
225
+ it ( "Multiple attestations with same attestation data different committee" , ( ) => {
226
+ // Attestation from committtee 0
227
+ const committeeBits0 = BitArray . fromSingleBit ( MAX_COMMITTEES_PER_SLOT , 0 )
228
+
229
+ const attestation0 : Attestation < ForkPostElectra > = {
230
+ ...attestation ,
231
+ aggregationBits : new BitArray ( new Uint8Array ( committeeLength / 8 ) . fill ( 1 ) , committeeLength ) ,
232
+ committeeBits : committeeBits0 ,
233
+ }
234
+
235
+ // Attestation from committtee 1
236
+ const committeeBits1 = BitArray . fromSingleBit ( MAX_COMMITTEES_PER_SLOT , 1 )
237
+
238
+ const attestation1 : Attestation < ForkPostElectra > = {
239
+ ...attestation ,
240
+ aggregationBits : new BitArray ( new Uint8Array ( committeeLength / 8 ) . fill ( 1 ) , committeeLength ) ,
241
+ committeeBits : committeeBits1 ,
242
+ }
243
+ // Attestation from committtee 2
244
+ const committeeBits2 = BitArray . fromSingleBit ( MAX_COMMITTEES_PER_SLOT , 2 )
245
+
246
+ const attestation2 : Attestation < ForkPostElectra > = {
247
+ ...attestation ,
248
+ aggregationBits : new BitArray ( new Uint8Array ( committeeLength / 8 ) . fill ( 1 ) , committeeLength ) ,
249
+ committeeBits : committeeBits2 ,
250
+ }
251
+
252
+ // Attestation from committtee 3
253
+ const committeeBits3 = BitArray . fromSingleBit ( MAX_COMMITTEES_PER_SLOT , 3 )
254
+
255
+ const attestation3 : Attestation < ForkPostElectra > = {
256
+ ...attestation ,
257
+ aggregationBits : new BitArray ( new Uint8Array ( committeeLength / 8 ) . fill ( 1 ) , committeeLength ) ,
258
+ committeeBits : committeeBits3 ,
259
+ }
260
+
261
+ pool . add (
262
+ attestation0 ,
263
+ attDataRootHex ,
264
+ attestation0 . aggregationBits . getTrueBitIndexes ( ) . length ,
265
+ committees [ 0 ] ,
266
+ ) ;
267
+
268
+ pool . add (
269
+ attestation1 ,
270
+ attDataRootHex ,
271
+ attestation0 . aggregationBits . getTrueBitIndexes ( ) . length ,
272
+ committees [ 1 ] ,
273
+ ) ;
274
+
275
+ pool . add (
276
+ attestation2 ,
277
+ attDataRootHex ,
278
+ attestation0 . aggregationBits . getTrueBitIndexes ( ) . length ,
279
+ committees [ 2 ] ,
280
+ ) ;
281
+
282
+ pool . add (
283
+ attestation3 ,
284
+ attDataRootHex ,
285
+ attestation0 . aggregationBits . getTrueBitIndexes ( ) . length ,
286
+ committees [ 3 ] ,
287
+ ) ;
288
+
289
+ forkchoiceStub . getBlockHex . mockReturnValue ( generateProtoBlock ( ) ) ;
290
+ forkchoiceStub . getDependentRoot . mockReturnValue ( ZERO_HASH_HEX ) ;
291
+
292
+ const blockAttestations = pool . getAttestationsForBlock ( fork , forkchoiceStub , electraState ) ;
293
+
294
+ expect ( blockAttestations . length ) . toBe ( 1 ) ; // Expect attestations from committee 0, 1, 2 and 3 to be aggregated into one
295
+ expect ( ( blockAttestations [ 0 ] as Attestation < ForkPostElectra > ) . committeeBits . getTrueBitIndexes ( ) ) . toStrictEqual ( committeeIndices ) ;
296
+
297
+ } )
298
+ } ) ;
299
+
161
300
describe ( "MatchingDataAttestationGroup.add()" , ( ) => {
162
301
const testCases : { id : string ; attestationsToAdd : { bits : number [ ] ; res : InsertOutcome ; isKept : boolean } [ ] } [ ] = [
163
302
{
0 commit comments