Skip to content

Commit 2d390f9

Browse files
authored
test: correct lightclient committee root test for electra (ChainSafe#8825)
## Description Fixes the failing lightclient e2e test after upgrading to electra. ### Root Cause The test incorrectly assumed sync committees would have alternating pubkeys `[pk0, pk1, pk0, pk1, ...]`: ```typescript const committeePubkeys = Array.from({length: SYNC_COMMITTEE_SIZE}, (_, i) => i % 2 === 0 ? pubkeys[0] : pubkeys[1] ); ``` However, sync committees are computed using a **weighted random shuffle** based on: - A seed derived from the state - Validator effective balances ### Why it broke post-electra In `getNextSyncCommitteeIndices()`, the shuffle parameters changed for electra: ```typescript if (fork >= ForkSeq.electra) { maxEffectiveBalance = MAX_EFFECTIVE_BALANCE_ELECTRA; // Different! randByteCount = 2; // Different! (was 1) } ``` The shuffle algorithm now uses 2 random bytes instead of 1, producing a completely different committee distribution even with the same validators. ### Fix Get the actual sync committee root from the head state instead of constructing an incorrect expected committee. Closes ChainSafe#8723 --- > [!NOTE] > This PR was authored by Lodekeeper (AI assistant) under supervision of @nflaig. --------- Co-authored-by: lodekeeper <lodekeeper@users.noreply.github.com>
1 parent 1020f27 commit 2d390f9

1 file changed

Lines changed: 12 additions & 21 deletions

File tree

packages/beacon-node/test/e2e/api/impl/lightclient/endpoint.test.ts

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {afterEach, beforeEach, describe, expect, it} from "vitest";
2-
import {aggregateSerializedPublicKeys} from "@chainsafe/blst";
32
import {HttpHeader, getClient, routes} from "@lodestar/api";
43
import {ChainConfig, createBeaconConfig} from "@lodestar/config";
5-
import {ForkName, SYNC_COMMITTEE_SIZE} from "@lodestar/params";
6-
import {phase0, ssz} from "@lodestar/types";
4+
import {ForkName} from "@lodestar/params";
5+
import {CachedBeaconStateAltair} from "@lodestar/state-transition";
6+
import {phase0} from "@lodestar/types";
77
import {sleep} from "@lodestar/utils";
88
import {Validator} from "@lodestar/validator";
99
import {BeaconNode} from "../../../../../src/node/nodejs.js";
@@ -119,29 +119,20 @@ describe("lightclient api", () => {
119119
expect(finalityUpdate).toBeDefined();
120120
});
121121

122-
it.skip("getLightClientCommitteeRoot() for the 1st period", async () => {
123-
// need to investigate why this test fails after upgrading to electra
124-
// TODO: https://github.com/ChainSafe/lodestar/issues/8723
122+
it("getLightClientCommitteeRoot() for the 1st period", async () => {
125123
await waitForBestUpdate();
126124

127125
const lightclient = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).lightclient;
128126
const committeeRes = await lightclient.getLightClientCommitteeRoot({startPeriod: 0, count: 1});
129127
committeeRes.assertOk();
130-
const client = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).beacon;
131-
const validators = (await client.postStateValidators({stateId: "head"})).value();
132-
const pubkeys = validators.map((v) => v.validator.pubkey);
133-
expect(pubkeys.length).toBe(validatorCount);
134-
// only 2 validators spreading to 512 committee slots
135-
const committeePubkeys = Array.from({length: SYNC_COMMITTEE_SIZE}, (_, i) =>
136-
i % 2 === 0 ? pubkeys[0] : pubkeys[1]
137-
);
138-
const aggregatePubkey = aggregateSerializedPublicKeys(committeePubkeys).toBytes();
128+
129+
// Get the actual sync committee root from the head state
130+
// The sync committee is computed using a weighted random shuffle, not simple alternation
131+
// Since the test starts at Electra, headState is always post-Altair and has currentSyncCommittee
132+
const headState = bn.chain.getHeadState() as CachedBeaconStateAltair;
133+
const expectedRoot = headState.currentSyncCommittee.hashTreeRoot();
134+
139135
// single committee hash since we requested for the first period
140-
expect(committeeRes.value()).toEqual([
141-
ssz.altair.SyncCommittee.hashTreeRoot({
142-
pubkeys: committeePubkeys,
143-
aggregatePubkey,
144-
}),
145-
]);
136+
expect(committeeRes.value()).toEqual([expectedRoot]);
146137
});
147138
});

0 commit comments

Comments
 (0)