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

fix: cached balances in epoch transition #7018

Merged
merged 2 commits into from
Aug 13, 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 @@ -75,6 +75,7 @@ export function processAttestationsAltair(
// For each participant, update their participation
// In epoch processing, this participation info is used to calculate balance updates
let totalBalanceIncrementsWithWeight = 0;
const validators = state.validators;
for (const index of attestingIndices) {
const flags = epochParticipation.get(index);

Expand Down Expand Up @@ -104,7 +105,7 @@ export function processAttestationsAltair(
// TODO: describe issue. Compute progressive target balances
// When processing each attestation, increase the cummulative target balance. Only applies post-altair
if ((flagsNewSet & TIMELY_TARGET) === TIMELY_TARGET) {
const validator = state.validators.getReadonly(index);
const validator = validators.getReadonly(index);
if (!validator.slashed) {
if (inCurrentEpoch) {
epochCtx.currentTargetUnslashedBalanceIncrements += effectiveBalanceIncrements[index];
Expand Down
4 changes: 2 additions & 2 deletions packages/state-transition/src/epoch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@ export function processEpoch(
const timer = metrics?.epochTransitionStepTime.startTimer({
step: EpochTransitionStep.processPendingBalanceDeposits,
});
processPendingBalanceDeposits(stateElectra);
processPendingBalanceDeposits(stateElectra, cache);
timer?.();
}

{
const timer = metrics?.epochTransitionStepTime.startTimer({
step: EpochTransitionStep.processPendingConsolidations,
});
processPendingConsolidations(stateElectra);
processPendingConsolidations(stateElectra, cache);
timer?.();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ export function processEffectiveBalanceUpdates(

// update effective balances with hysteresis

// epochTransitionCache.balances is set in processRewardsAndPenalties(), so it's recycled here for performance.
// It defaults to `state.balances.getAll()` to make Typescript happy and for spec tests
const balances = state.balances.getAll();

// TODO: (@matthewkeil) This was causing additional failures but should not. Check the EpochTransitionCache for why
// const balances = cache.balances ?? state.balances.getAll();
// epochTransitionCache.balances is initialized in processRewardsAndPenalties()
// and updated in processPendingBalanceDeposits() and processPendingConsolidations()
// so it's recycled here for performance.
const balances = cache.balances ?? state.balances.getAll();

for (let i = 0, len = balances.length; i < len; i++) {
const balance = balances[i];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {FAR_FUTURE_EPOCH} from "@lodestar/params";
import {CachedBeaconStateElectra} from "../types.js";
import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js";
import {increaseBalance} from "../util/balance.js";
import {getActivationExitChurnLimit} from "../util/validator.js";
import {getCurrentEpoch} from "../util/epoch.js";
Expand All @@ -13,24 +13,29 @@ import {getCurrentEpoch} from "../util/epoch.js";
*
* TODO Electra: Update ssz library to support batch push to `pendingBalanceDeposits`
*/
export function processPendingBalanceDeposits(state: CachedBeaconStateElectra): void {
export function processPendingBalanceDeposits(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void {
const availableForProcessing = state.depositBalanceToConsume + BigInt(getActivationExitChurnLimit(state.epochCtx));
const currentEpoch = getCurrentEpoch(state);
let processedAmount = 0n;
let nextDepositIndex = 0;
const depositsToPostpone = [];
const validators = state.validators;
const cachedBalances = cache.balances;

for (const deposit of state.pendingBalanceDeposits.getAllReadonly()) {
const {amount, index: depositIndex} = deposit;
const validator = state.validators.get(depositIndex);
const validator = validators.getReadonly(depositIndex);

// Validator is exiting, postpone the deposit until after withdrawable epoch
if (validator.exitEpoch < FAR_FUTURE_EPOCH) {
if (currentEpoch <= validator.withdrawableEpoch) {
depositsToPostpone.push(deposit);
} else {
// Deposited balance will never become active. Increase balance but do not consume churn
increaseBalance(state, deposit.index, Number(amount));
increaseBalance(state, depositIndex, Number(amount));
if (cachedBalances) {
cachedBalances[depositIndex] += Number(amount);
}
}
} else {
// Validator is not exiting, attempt to process deposit
Expand All @@ -39,7 +44,10 @@ export function processPendingBalanceDeposits(state: CachedBeaconStateElectra):
break;
} else {
// Deposit fits in the churn, process it. Increase balance and consume churn.
increaseBalance(state, deposit.index, Number(amount));
increaseBalance(state, depositIndex, Number(amount));
if (cachedBalances) {
cachedBalances[depositIndex] += Number(amount);
}
processedAmount = processedAmount + amount;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {CachedBeaconStateElectra} from "../types.js";
import {CachedBeaconStateElectra, EpochTransitionCache} from "../types.js";
import {decreaseBalance, increaseBalance} from "../util/balance.js";
import {getActiveBalance} from "../util/validator.js";
import {switchToCompoundingValidator} from "../util/electra.js";
Expand All @@ -16,12 +16,14 @@ import {switchToCompoundingValidator} from "../util/electra.js";
* Dequeue all processed consolidations from `state.pendingConsolidation`
*
*/
export function processPendingConsolidations(state: CachedBeaconStateElectra): void {
export function processPendingConsolidations(state: CachedBeaconStateElectra, cache: EpochTransitionCache): void {
let nextPendingConsolidation = 0;
const validators = state.validators;
const cachedBalances = cache.balances;

for (const pendingConsolidation of state.pendingConsolidations.getAllReadonly()) {
const {sourceIndex, targetIndex} = pendingConsolidation;
const sourceValidator = state.validators.getReadonly(sourceIndex);
const sourceValidator = validators.getReadonly(sourceIndex);

if (sourceValidator.slashed) {
nextPendingConsolidation++;
Expand All @@ -37,6 +39,10 @@ export function processPendingConsolidations(state: CachedBeaconStateElectra): v
const activeBalance = getActiveBalance(state, sourceIndex);
decreaseBalance(state, sourceIndex, activeBalance);
increaseBalance(state, targetIndex, activeBalance);
if (cachedBalances) {
cachedBalances[sourceIndex] -= activeBalance;
cachedBalances[targetIndex] += activeBalance;
}

nextPendingConsolidation++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ export function processSyncCommitteeUpdates(fork: ForkSeq, state: CachedBeaconSt
activeValidatorIndices,
effectiveBalanceIncrements
);
const validators = state.validators;

// Using the index2pubkey cache is slower because it needs the serialized pubkey.
const nextSyncCommitteePubkeys = nextSyncCommitteeIndices.map(
(index) => state.validators.getReadonly(index).pubkey
);
const nextSyncCommitteePubkeys = nextSyncCommitteeIndices.map((index) => validators.getReadonly(index).pubkey);

// Rotate syncCommittee in state
state.currentSyncCommittee = state.nextSyncCommittee;
Expand Down
Loading