Skip to content

Commit

Permalink
caching epoch seed in context so that getNextEpochBeaconProposer can …
Browse files Browse the repository at this point in the history
…be independent of state
  • Loading branch information
dadepo committed Apr 29, 2022
1 parent d54e124 commit 02a722a
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 10 deletions.
24 changes: 20 additions & 4 deletions packages/beacon-state-transition/src/cache/epochContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {BLSSignature, CommitteeIndex, Epoch, Slot, ValidatorIndex, phase0, SyncP
import {createIBeaconConfig, IBeaconConfig, IChainConfig} from "@chainsafe/lodestar-config";
import {
ATTESTATION_SUBNET_COUNT,
DOMAIN_BEACON_PROPOSER,
EFFECTIVE_BALANCE_INCREMENT,
FAR_FUTURE_EPOCH,
GENESIS_EPOCH,
Expand All @@ -20,6 +21,7 @@ import {
isAggregatorFromCommitteeLength,
computeProposers,
computeSyncPeriodAtEpoch,
getSeed,
} from "../util";
import {computeEpochShuffling, IEpochShuffling} from "../util/epochShuffling";
import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsWithLen} from "./effectiveBalanceIncrements";
Expand Down Expand Up @@ -161,6 +163,8 @@ export class EpochContext {
epoch: Epoch;
syncPeriod: SyncPeriod;

beaconProposerEpochSeed: Uint8Array;

constructor(data: {
config: IBeaconConfig;
pubkey2index: PubkeyIndexMap;
Expand All @@ -181,6 +185,7 @@ export class EpochContext {
nextSyncCommitteeIndexed: SyncCommitteeCache;
epoch: Epoch;
syncPeriod: SyncPeriod;
beaconProposerEpochSeed: Uint8Array;
}) {
this.config = data.config;
this.pubkey2index = data.pubkey2index;
Expand All @@ -201,6 +206,7 @@ export class EpochContext {
this.nextSyncCommitteeIndexed = data.nextSyncCommitteeIndexed;
this.epoch = data.epoch;
this.syncPeriod = data.syncPeriod;
this.beaconProposerEpochSeed = data.beaconProposerEpochSeed;
}

/**
Expand Down Expand Up @@ -280,9 +286,13 @@ export class EpochContext {
: computeEpochShuffling(state, previousActiveIndices, previousEpoch);
const nextShuffling = computeEpochShuffling(state, nextActiveIndices, nextEpoch);

const beaconProposerEpochSeed = getSeed(state, currentShuffling.epoch, DOMAIN_BEACON_PROPOSER);

// Allow to create CachedBeaconState for empty states
const proposers =
state.validators.length > 0 ? computeProposers(state, currentShuffling, effectiveBalanceIncrements) : [];
state.validators.length > 0
? computeProposers(beaconProposerEpochSeed, currentShuffling, effectiveBalanceIncrements)
: [];

// Only after altair, compute the indices of the current sync committee
const afterAltairFork = currentEpoch >= config.ALTAIR_FORK_EPOCH;
Expand Down Expand Up @@ -345,6 +355,7 @@ export class EpochContext {
nextSyncCommitteeIndexed,
epoch: currentEpoch,
syncPeriod: computeSyncPeriodAtEpoch(currentEpoch),
beaconProposerEpochSeed: beaconProposerEpochSeed,
});
}

Expand Down Expand Up @@ -380,6 +391,7 @@ export class EpochContext {
nextSyncCommitteeIndexed: this.nextSyncCommitteeIndexed,
epoch: this.epoch,
syncPeriod: this.syncPeriod,
beaconProposerEpochSeed: this.beaconProposerEpochSeed,
});
}

Expand All @@ -400,7 +412,11 @@ export class EpochContext {
const nextEpoch = currEpoch + 1;

this.nextShuffling = computeEpochShuffling(state, epochProcess.nextEpochShufflingActiveValidatorIndices, nextEpoch);
this.proposers = computeProposers(state, this.currentShuffling, this.effectiveBalanceIncrements);
this.proposers = computeProposers(
this.beaconProposerEpochSeed,
this.currentShuffling,
this.effectiveBalanceIncrements
);

// TODO: DEDUPLICATE from createEpochContext
//
Expand Down Expand Up @@ -478,11 +494,11 @@ export class EpochContext {
return (committeesSinceEpochStart + committeeIndex) % ATTESTATION_SUBNET_COUNT;
}

getNextEpochBeaconProposer(state: BeaconStateAllForks): ValidatorIndex[] {
getNextEpochBeaconProposer(): ValidatorIndex[] {
const nextShuffling = this.nextShuffling;
let nextProposers = this.nextEpochProposers.get(nextShuffling.epoch);
if (!nextProposers) {
nextProposers = computeProposers(state, nextShuffling, this.effectiveBalanceIncrements);
nextProposers = computeProposers(this.beaconProposerEpochSeed, nextShuffling, this.effectiveBalanceIncrements);
// Only keep proposers for one epoch in the future, so clear before setting new value
this.nextEpochProposers.clear();
this.nextEpochProposers.set(nextShuffling.epoch, nextProposers);
Expand Down
4 changes: 1 addition & 3 deletions packages/beacon-state-transition/src/util/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {digest} from "@chainsafe/as-sha256";
import {Epoch, Bytes32, DomainType, ValidatorIndex} from "@chainsafe/lodestar-types";
import {assert, bytesToBigInt, intToBytes} from "@chainsafe/lodestar-utils";
import {
DOMAIN_BEACON_PROPOSER,
DOMAIN_SYNC_COMMITTEE,
EFFECTIVE_BALANCE_INCREMENT,
EPOCHS_PER_HISTORICAL_VECTOR,
Expand All @@ -25,11 +24,10 @@ import {computeEpochAtSlot} from "./epoch";
* Compute proposer indices for an epoch
*/
export function computeProposers(
state: BeaconStateAllForks,
epochSeed: Uint8Array,
shuffling: {epoch: Epoch; activeIndices: ValidatorIndex[]},
effectiveBalanceIncrements: EffectiveBalanceIncrements
): number[] {
const epochSeed = getSeed(state, shuffling.epoch, DOMAIN_BEACON_PROPOSER);
const startSlot = computeStartSlotAtEpoch(shuffling.epoch);
const proposers = [];
for (let slot = startSlot; slot < startSlot + SLOTS_PER_EPOCH; slot++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import {itBench} from "@dapplion/benchmark";
import {Epoch} from "@chainsafe/lodestar-types";
import {DOMAIN_BEACON_PROPOSER} from "@chainsafe/lodestar-params";
import {
computeEpochAtSlot,
CachedBeaconStateAllForks,
computeEpochShuffling,
getNextSyncCommittee,
} from "../../../../src";
import {computeProposers} from "../../../../src";
import {getSeed} from "../../../../lib";
import {generatePerfTestCachedStatePhase0, numValidators} from "../../util";
import {computeProposers} from "../../../../src/util/seed";

describe("epoch shufflings", () => {
let state: CachedBeaconStateAllForks;
Expand All @@ -25,7 +27,8 @@ describe("epoch shufflings", () => {
itBench({
id: `computeProposers - vc ${numValidators}`,
fn: () => {
computeProposers(state, state.epochCtx.nextShuffling, state.epochCtx.effectiveBalanceIncrements);
const epochSeed = getSeed(state, state.epochCtx.nextShuffling.epoch, DOMAIN_BEACON_PROPOSER);
computeProposers(epochSeed, state.epochCtx.nextShuffling, state.epochCtx.effectiveBalanceIncrements);
},
});

Expand Down
2 changes: 1 addition & 1 deletion packages/lodestar/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ export function getValidatorApi({chain, config, logger, metrics, network, sync}:
// Note: There is a small probability that returned validators differs
// than what is returned when the epoch is reached.
if (epoch === nextEpoch) {
indexes.push(...state.epochCtx.getNextEpochBeaconProposer(state));
indexes.push(...state.epochCtx.getNextEpochBeaconProposer());
} else {
// Gather indexes to get pubkeys in batch (performance optimization)
for (let i = 0; i < SLOTS_PER_EPOCH; i++) {
Expand Down

0 comments on commit 02a722a

Please sign in to comment.