Skip to content

Commit

Permalink
feat: use 16-bit random value to compute validator indices (#7311)
Browse files Browse the repository at this point in the history
  • Loading branch information
nflaig authored Dec 18, 2024
1 parent 031214e commit cd7b1b4
Showing 1 changed file with 79 additions and 51 deletions.
130 changes: 79 additions & 51 deletions packages/state-transition/src/util/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
SYNC_COMMITTEE_SIZE,
} from "@lodestar/params";
import {Bytes32, DomainType, Epoch, ValidatorIndex} from "@lodestar/types";
import {assert, bytesToBigInt, intToBytes} from "@lodestar/utils";
import {assert, bytesToBigInt, bytesToInt, intToBytes} from "@lodestar/utils";
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
import {BeaconStateAllForks} from "../types.js";
import {computeStartSlotAtEpoch} from "./epoch.js";
Expand Down Expand Up @@ -57,30 +57,40 @@ export function computeProposerIndex(
throw Error("Validator indices must not be empty");
}

// TODO: Inline outside this function
const MAX_RANDOM_BYTE = 2 ** 8 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT =
fork >= ForkSeq.electra
? MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT
: MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT;

let i = 0;
/* eslint-disable-next-line no-constant-condition */
while (true) {
const candidateIndex = indices[computeShuffledIndex(i % indices.length, indices.length, seed)];
const randByte = digest(
Buffer.concat([
seed,
//
intToBytes(Math.floor(i / 32), 8, "le"),
])
)[i % 32];

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randByte) {
return candidateIndex;
if (fork >= ForkSeq.electra) {
const MAX_RANDOM_VALUE = 2 ** 16 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT;

let i = 0;
while (true) {
const candidateIndex = indices[computeShuffledIndex(i % indices.length, indices.length, seed)];
const randomBytes = digest(Buffer.concat([seed, intToBytes(Math.floor(i / 16), 8, "le")]));
const offset = (i % 16) * 2;
const randomValue = bytesToInt(randomBytes.subarray(offset, offset + 2));

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randomValue) {
return candidateIndex;
}

i += 1;
}
} else {
const MAX_RANDOM_BYTE = 2 ** 8 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT;

let i = 0;
while (true) {
const candidateIndex = indices[computeShuffledIndex(i % indices.length, indices.length, seed)];
const randomByte = digest(Buffer.concat([seed, intToBytes(Math.floor(i / 32), 8, "le")]))[i % 32];

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randomByte) {
return candidateIndex;
}

i += 1;
}
i += 1;
}
}

Expand All @@ -100,37 +110,55 @@ export function getNextSyncCommitteeIndices(
activeValidatorIndices: ArrayLike<ValidatorIndex>,
effectiveBalanceIncrements: EffectiveBalanceIncrements
): ValidatorIndex[] {
// TODO: Bechmark if it's necessary to inline outside of this function
const MAX_RANDOM_BYTE = 2 ** 8 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT =
fork >= ForkSeq.electra
? MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT
: MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT;

const epoch = computeEpochAtSlot(state.slot) + 1;

const activeValidatorCount = activeValidatorIndices.length;
const seed = getSeed(state, epoch, DOMAIN_SYNC_COMMITTEE);
let i = 0;
const syncCommitteeIndices = [];
while (syncCommitteeIndices.length < SYNC_COMMITTEE_SIZE) {
const shuffledIndex = computeShuffledIndex(i % activeValidatorCount, activeValidatorCount, seed);
const candidateIndex = activeValidatorIndices[shuffledIndex];
const randByte = digest(
Buffer.concat([
seed,
//
intToBytes(Math.floor(i / 32), 8, "le"),
])
)[i % 32];

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randByte) {
syncCommitteeIndices.push(candidateIndex);

if (fork >= ForkSeq.electra) {
const MAX_RANDOM_VALUE = 2 ** 16 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE_ELECTRA / EFFECTIVE_BALANCE_INCREMENT;

const epoch = computeEpochAtSlot(state.slot) + 1;
const activeValidatorCount = activeValidatorIndices.length;
const seed = getSeed(state, epoch, DOMAIN_SYNC_COMMITTEE);

let i = 0;
while (syncCommitteeIndices.length < SYNC_COMMITTEE_SIZE) {
const shuffledIndex = computeShuffledIndex(i % activeValidatorCount, activeValidatorCount, seed);
const candidateIndex = activeValidatorIndices[shuffledIndex];
const randomBytes = digest(Buffer.concat([seed, intToBytes(Math.floor(i / 16), 8, "le")]));
const offset = (i % 16) * 2;
const randomValue = bytesToInt(randomBytes.subarray(offset, offset + 2));

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_VALUE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randomValue) {
syncCommitteeIndices.push(candidateIndex);
}

i += 1;
}
} else {
const MAX_RANDOM_BYTE = 2 ** 8 - 1;
const MAX_EFFECTIVE_BALANCE_INCREMENT = MAX_EFFECTIVE_BALANCE / EFFECTIVE_BALANCE_INCREMENT;

const epoch = computeEpochAtSlot(state.slot) + 1;

const activeValidatorCount = activeValidatorIndices.length;
const seed = getSeed(state, epoch, DOMAIN_SYNC_COMMITTEE);

i++;
let i = 0;
while (syncCommitteeIndices.length < SYNC_COMMITTEE_SIZE) {
const shuffledIndex = computeShuffledIndex(i % activeValidatorCount, activeValidatorCount, seed);
const candidateIndex = activeValidatorIndices[shuffledIndex];
const randomByte = digest(Buffer.concat([seed, intToBytes(Math.floor(i / 32), 8, "le")]))[i % 32];

const effectiveBalanceIncrement = effectiveBalanceIncrements[candidateIndex];
if (effectiveBalanceIncrement * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_INCREMENT * randomByte) {
syncCommitteeIndices.push(candidateIndex);
}

i += 1;
}
}

return syncCommitteeIndices;
}

Expand Down

0 comments on commit cd7b1b4

Please sign in to comment.