Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use POST variant to get validators from state #6897

Merged
merged 4 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe("lightclient api", function () {
const committeeRes = await lightclient.getLightClientCommitteeRoot({startPeriod: 0, count: 1});
committeeRes.assertOk();
const client = getClient({baseUrl: `http://127.0.0.1:${restPort}`}, {config}).beacon;
const validators = (await client.getStateValidators({stateId: "head"})).value();
const validators = (await client.postStateValidators({stateId: "head"})).value();
const pubkeys = validators.map((v) => v.validator.pubkey);
expect(pubkeys.length).toBe(validatorCount);
// only 2 validators spreading to 512 committee slots
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/validator/blsToExecutionChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ like to choose for BLS To Execution Change.",
const {genesisValidatorsRoot} = (await client.beacon.getGenesis()).value();
const config = createBeaconConfig(chainForkConfig, genesisValidatorsRoot);

const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: [publicKey]})).value();
const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: [publicKey]})).value();
const validator = validators[0];
if (validator === undefined) {
throw new Error(`Validator pubkey ${publicKey} not found in state`);
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cmds/validator/voluntaryExit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ function selectSignersToExit(args: VoluntaryExitArgs, signers: Signer[]): Signer
async function resolveValidatorIndexes(client: ApiClient, signersToExit: SignerPubkey[]) {
const pubkeys = signersToExit.map(({pubkey}) => pubkey);

const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pubkeys})).value();
const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pubkeys})).value();

const dataByPubkey = new Map(validators.map((item) => [toPubkeyHex(item.validator.pubkey), item]));

Expand Down
10 changes: 5 additions & 5 deletions packages/cli/test/sim/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ await env.start({runTimeoutMs: estimatedTimeoutMs});
const node = env.nodes[0].beacon;
await waitForSlot("Wait for 2 slots before checking endpoints", {env, slot: 2});

const validators = (await node.api.beacon.getStateValidators({stateId: "head"})).value();
const validators = (await node.api.beacon.postStateValidators({stateId: "head"})).value();

await env.tracker.assert("should have correct validators count called without filters", async () => {
assert.equal(validators.length, validatorCount);
Expand All @@ -55,12 +55,12 @@ await env.tracker.assert("should have correct validator index for second validat
});

await env.tracker.assert(
"should return correct number of filtered validators when getStateValidators called with filters",
"should return correct number of filtered validators when postStateValidators called with filters",
async () => {
const filterPubKey =
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c";

const res = await node.api.beacon.getStateValidators({stateId: "head", validatorIds: [filterPubKey]});
const res = await node.api.beacon.postStateValidators({stateId: "head", validatorIds: [filterPubKey]});

assert.equal(res.value().length, 1);

Expand All @@ -71,12 +71,12 @@ await env.tracker.assert(
);

await env.tracker.assert(
"should return correct filtered validators when getStateValidators called with filters",
"should return correct filtered validators when postStateValidators called with filters",
async () => {
const filterPubKey =
"0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c";

const res = await node.api.beacon.getStateValidators({stateId: "head", validatorIds: [filterPubKey]});
const res = await node.api.beacon.postStateValidators({stateId: "head", validatorIds: [filterPubKey]});

assert.equal(toHexString(res.value()[0].validator.pubkey), filterPubKey);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/flare/src/cmds/selfSlashAttester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise<voi

// Retrieve the status all all validators in range at once
const pksHex = sks.map((sk) => sk.toPublicKey().toHex());
const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pksHex})).value();
const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pksHex})).value();

// All validators in the batch will be part of the same AttesterSlashing
const attestingIndices = validators.map((v) => v.index);
Expand All @@ -92,7 +92,7 @@ export async function selfSlashAttesterHandler(args: SelfSlashArgs): Promise<voi
const pkHex = pksHex[i];
const validatorPkHex = toPubkeyHex(validator.pubkey);
if (validatorPkHex !== pkHex) {
throw Error(`getStateValidators did not return same validator pubkey: ${validatorPkHex} != ${pkHex}`);
throw Error(`Beacon node did not return same validator pubkey: ${validatorPkHex} != ${pkHex}`);
}

if (status === "active_slashed" || status === "exited_slashed") {
Expand Down
4 changes: 2 additions & 2 deletions packages/flare/src/cmds/selfSlashProposer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export async function selfSlashProposerHandler(args: SelfSlashArgs): Promise<voi

// Retrieve the status all all validators in range at once
const pksHex = sks.map((sk) => sk.toPublicKey().toHex());
const validators = (await client.beacon.getStateValidators({stateId: "head", validatorIds: pksHex})).value();
const validators = (await client.beacon.postStateValidators({stateId: "head", validatorIds: pksHex})).value();

// Submit all ProposerSlashing for range at once
await Promise.all(
Expand All @@ -88,7 +88,7 @@ export async function selfSlashProposerHandler(args: SelfSlashArgs): Promise<voi
try {
const validatorPkHex = toPubkeyHex(validator.pubkey);
if (validatorPkHex !== pkHex) {
throw Error(`getStateValidators did not return same validator pubkey: ${validatorPkHex} != ${pkHex}`);
throw Error(`Beacon node did not return same validator pubkey: ${validatorPkHex} != ${pkHex}`);
}

if (status === "active_slashed" || status === "exited_slashed") {
Expand Down
12 changes: 7 additions & 5 deletions packages/validator/src/services/indices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {batchItems} from "../util/index.js";
import {Metrics} from "../metrics.js";

/**
* URLs have a limitation on size, adding an unbounded num of pubkeys will break the request.
* For reasoning on the specific number see: https://github.com/ethereum/beacon-APIs/pull/328
* This is to prevent the "Request body is too large" issue for http post.
* Typical servers accept up to 1MB (2 ** 20 bytes) of request body, for example fastify and nginx.
* A hex encoded public key with "0x"-prefix has a size of 98 bytes + 2 bytes to account for commas
* and other JSON padding. `Math.floor(2 ** 20 / 100) == 10485`, we can send up to ~10k keys per request.
*/
const PUBKEYS_PER_REQUEST = 64;
const PUBKEYS_PER_REQUEST = 10_000;

// To assist with readability
type PubkeyHex = string;
Expand Down Expand Up @@ -108,7 +110,7 @@ export class IndicesService {
}

// Query the remote BN to resolve a pubkey to a validator index.
// support up to 1000 pubkeys per poll
// support up to 10k pubkeys per poll
const pubkeysHexBatches = batchItems(pubkeysHexToDiscover, {batchSize: PUBKEYS_PER_REQUEST});

const newIndices: number[] = [];
Expand All @@ -123,7 +125,7 @@ export class IndicesService {
}

private async fetchValidatorIndices(pubkeysHex: string[]): Promise<ValidatorIndex[]> {
const validators = (await this.api.beacon.getStateValidators({stateId: "head", validatorIds: pubkeysHex})).value();
const validators = (await this.api.beacon.postStateValidators({stateId: "head", validatorIds: pubkeysHex})).value();

const newIndices = [];

Expand Down
4 changes: 3 additions & 1 deletion packages/validator/src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,9 @@ export class Validator {
* Create a signed voluntary exit message for the given validator by its key.
*/
async signVoluntaryExit(publicKey: string, exitEpoch?: number): Promise<phase0.SignedVoluntaryExit> {
const validators = (await this.api.beacon.getStateValidators({stateId: "head", validatorIds: [publicKey]})).value();
const validators = (
await this.api.beacon.postStateValidators({stateId: "head", validatorIds: [publicKey]})
).value();

const validator = validators[0];
if (validator === undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe("AttestationService", function () {
];

// Return empty replies to duties service
api.beacon.getStateValidators.mockResolvedValue(
api.beacon.postStateValidators.mockResolvedValue(
mockApiResponse({data: [], meta: {executionOptimistic: false, finalized: false}})
);
api.validator.getAttesterDuties.mockResolvedValue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ describe("AttestationDutiesService", function () {
index,
validator: {...defaultValidator.validator, pubkey: pubkeys[0]},
};
api.beacon.getStateValidators.mockResolvedValue(
api.beacon.postStateValidators.mockResolvedValue(
mockApiResponse({data: [validatorResponse], meta: {executionOptimistic: false, finalized: false}})
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe("SyncCommitteeDutiesService", function () {
index: indices[i],
validator: {...defaultValidator.validator, pubkey: pubkeys[i]},
}));
api.beacon.getStateValidators.mockResolvedValue(
api.beacon.postStateValidators.mockResolvedValue(
mockApiResponse({data: validatorResponses, meta: {executionOptimistic: false, finalized: false}})
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe("SyncCommitteeService", function () {
];

// Return empty replies to duties service
api.beacon.getStateValidators.mockResolvedValue(
api.beacon.postStateValidators.mockResolvedValue(
mockApiResponse({data: [], meta: {executionOptimistic: false, finalized: false}})
);
api.validator.getSyncCommitteeDuties.mockResolvedValue(
Expand Down
1 change: 1 addition & 0 deletions packages/validator/test/utils/apiStub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function getApiClientStub(): ApiClientStub {
return {
beacon: {
getStateValidators: vi.fn(),
postStateValidators: vi.fn(),
publishBlindedBlockV2: vi.fn(),
publishBlockV2: vi.fn(),
submitPoolSyncCommitteeSignatures: vi.fn(),
Expand Down
Loading