Skip to content

Commit 5e52471

Browse files
committed
add unit test
1 parent 1f9a9df commit 5e52471

File tree

2 files changed

+145
-6
lines changed

2 files changed

+145
-6
lines changed

packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts

+143-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import {createChainForkConfig, defaultChainConfig} from "@lodestar/config";
44
import {
55
FAR_FUTURE_EPOCH,
66
ForkName,
7+
ForkPostElectra,
78
MAX_COMMITTEES_PER_SLOT,
89
MAX_EFFECTIVE_BALANCE,
10+
MAX_VALIDATORS_PER_COMMITTEE,
911
SLOTS_PER_EPOCH,
1012
} from "@lodestar/params";
11-
import {CachedBeaconStateAllForks, newFilledArray} from "@lodestar/state-transition";
13+
import {CachedBeaconStateAllForks, CachedBeaconStateElectra, newFilledArray} from "@lodestar/state-transition";
1214
import {CachedBeaconStateAltair} from "@lodestar/state-transition/src/types.js";
13-
import {phase0, ssz} from "@lodestar/types";
15+
import {Attestation, phase0, ssz} from "@lodestar/types";
1416
import {afterEach, beforeAll, beforeEach, describe, expect, it, vi} from "vitest";
1517
import {
1618
AggregatedAttestationPool,
@@ -25,7 +27,7 @@ import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js";
2527
import {linspace} from "../../../../src/util/numpy.js";
2628
import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js";
2729
import {renderBitArray} from "../../../utils/render.js";
28-
import {generateCachedAltairState} from "../../../utils/state.js";
30+
import {generateCachedAltairState, generateCachedElectraState} from "../../../utils/state.js";
2931
import {generateProtoBlock} from "../../../utils/typeGenerator.js";
3032
import {generateValidators} from "../../../utils/validator.js";
3133

@@ -34,7 +36,7 @@ const validSignature = fromHexString(
3436
"0xb2afb700f6c561ce5e1b4fedaec9d7c06b822d38c720cf588adfda748860a940adf51634b6788f298c552de40183b5a203b2bbe8b7dd147f0bb5bc97080a12efbb631c8888cb31a99cc4706eb3711865b8ea818c10126e4d818b542e9dbf9ae8"
3537
);
3638

37-
describe("AggregatedAttestationPool", () => {
39+
describe("AggregatedAttestationPool - Altair", () => {
3840
let pool: AggregatedAttestationPool;
3941
const fork = ForkName.altair;
4042
const config = createChainForkConfig({
@@ -158,6 +160,143 @@ describe("AggregatedAttestationPool", () => {
158160
});
159161
});
160162

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+
161300
describe("MatchingDataAttestationGroup.add()", () => {
162301
const testCases: {id: string; attestationsToAdd: {bits: number[]; res: InsertOutcome; isKept: boolean}[]}[] = [
163302
{

packages/beacon-node/test/utils/state.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac
150150
/**
151151
* This generates state with default pubkey
152152
*/
153-
export function generateCachedElectraState(opts?: TestBeaconState): CachedBeaconStateElectra {
154-
const config = getConfig(ForkName.electra);
153+
export function generateCachedElectraState(opts?: TestBeaconState, electraForkEpoch = 0): CachedBeaconStateElectra {
154+
const config = getConfig(ForkName.electra, electraForkEpoch);
155155
const state = generateState(opts, config);
156156
return createCachedBeaconState(state as BeaconStateElectra, {
157157
config: createBeaconConfig(config, state.genesisValidatorsRoot),

0 commit comments

Comments
 (0)