Skip to content

Commit

Permalink
feat: apply ReusableListIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Jul 24, 2024
1 parent bff2090 commit 8e09d4c
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 21 deletions.
14 changes: 7 additions & 7 deletions packages/state-transition/src/block/processEth1Data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Node} from "@chainsafe/persistent-merkle-tree";
import {CompositeViewDU} from "@chainsafe/ssz";
import {CompositeViewDU, ReusableListIterator} from "@chainsafe/ssz";
import {EPOCHS_PER_ETH1_VOTING_PERIOD, SLOTS_PER_EPOCH} from "@lodestar/params";
import {phase0, ssz} from "@lodestar/types";
import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js";
Expand All @@ -26,7 +26,7 @@ export function processEth1Data(state: CachedBeaconStateAllForks, eth1Data: phas
/**
* This data is reused and never gc.
*/
const eth1DataVotes = new Array<CompositeViewDU<typeof ssz.phase0.Eth1Data>>();
const eth1DataVotes = new ReusableListIterator<CompositeViewDU<typeof ssz.phase0.Eth1Data>>();
/**
* Returns true if adding the given `eth1Data` to `state.eth1DataVotes` would
* result in a change to `state.eth1Data`.
Expand All @@ -52,11 +52,11 @@ export function becomesNewEth1Data(
// Then isEqualEth1DataView compares cached roots (HashObject as of Jan 2022) which is much cheaper
// than doing structural equality, which requires tree -> value conversions
let sameVotesCount = 0;
// const eth1DataVotes = state.eth1DataVotes.getAllReadonly();
eth1DataVotes.length = state.eth1DataVotes.length;
state.eth1DataVotes.getAllReadonly(eth1DataVotes);
for (let i = 0; i < eth1DataVotes.length; i++) {
if (isEqualEth1DataView(eth1DataVotes[i], newEth1Data)) {
eth1DataVotes.reset();
state.eth1DataVotes.getAllReadonlyIter(eth1DataVotes);
eth1DataVotes.clean();
for (const eth1DataVote of eth1DataVotes) {
if (isEqualEth1DataView(eth1DataVote, newEth1Data)) {
sameVotesCount++;
}
}
Expand Down
22 changes: 13 additions & 9 deletions packages/state-transition/src/cache/epochTransitionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../index.js";
import {computeBaseRewardPerIncrement} from "../util/altair.js";
import {processPendingAttestations} from "../epoch/processPendingAttestations.js";
import {ReusableListIterator} from "@chainsafe/ssz";

export type EpochTransitionCacheOpts = {
/**
Expand Down Expand Up @@ -200,7 +201,7 @@ const flags = new Array<number>();
/**
* This data is reused and never gc.
*/
const validators = new Array<phase0.Validator>();
const validators = new ReusableListIterator<phase0.Validator>();
const previousEpochParticipation = new Array<number>();
const currentEpochParticipation = new Array<number>();

Expand All @@ -221,7 +222,7 @@ export function beforeProcessEpoch(
const eligibleValidatorIndices: ValidatorIndex[] = [];
const indicesToSlash: ValidatorIndex[] = [];
const indicesEligibleForActivationQueue: ValidatorIndex[] = [];
const indicesEligibleForActivation: ValidatorIndex[] = [];
const indicesEligibleForActivation: {validatorIndex: ValidatorIndex; activationEligibilityEpoch: Epoch}[] = [];
const indicesToEject: ValidatorIndex[] = [];
const nextEpochShufflingActiveValidatorIndices: ValidatorIndex[] = [];

Expand All @@ -230,8 +231,9 @@ export function beforeProcessEpoch(
// To optimize memory each validator node in `state.validators` is represented with a special node type
// `BranchNodeStruct` that represents the data as struct internally. This utility grabs the struct data directly
// from the nodes without any extra transformation. The returned `validators` array contains native JS objects.
validators.length = state.validators.length;
state.validators.getAllReadonlyValues(validators);
validators.reset();
state.validators.getAllReadonlyValuesIter(validators);
validators.clean();

const validatorCount = validators.length;

Expand Down Expand Up @@ -266,8 +268,9 @@ export function beforeProcessEpoch(

const effectiveBalancesByIncrements = epochCtx.effectiveBalanceIncrements;

for (let i = 0; i < validatorCount; i++) {
const validator = validators[i];
// for (let i = 0; i < validatorCount; i++) {
let i = 0;
for (const validator of validators) {
let flag = 0;

if (validator.slashed) {
Expand Down Expand Up @@ -333,7 +336,7 @@ export function beforeProcessEpoch(
//
// Use `else` since indicesEligibleForActivationQueue + indicesEligibleForActivation are mutually exclusive
else if (validator.activationEpoch === FAR_FUTURE_EPOCH && validator.activationEligibilityEpoch <= currentEpoch) {
indicesEligibleForActivation.push(i);
indicesEligibleForActivation.push({validatorIndex: i, activationEligibilityEpoch: validator.activationEligibilityEpoch});
}

// To optimize process_registry_updates():
Expand All @@ -358,6 +361,7 @@ export function beforeProcessEpoch(
if (isActiveNext2) {
nextEpochShufflingActiveValidatorIndices.push(i);
}
i++;
}

if (totalActiveStakeByIncrement < 1) {
Expand All @@ -372,7 +376,7 @@ export function beforeProcessEpoch(
// To optimize process_registry_updates():
// order by sequence of activationEligibilityEpoch setting and then index
indicesEligibleForActivation.sort(
(a, b) => validators[a].activationEligibilityEpoch - validators[b].activationEligibilityEpoch || a - b
(a, b) => a.activationEligibilityEpoch - b.activationEligibilityEpoch || a.validatorIndex - b.validatorIndex
);

if (forkSeq === ForkSeq.phase0) {
Expand Down Expand Up @@ -480,7 +484,7 @@ export function beforeProcessEpoch(
eligibleValidatorIndices,
indicesToSlash,
indicesEligibleForActivationQueue,
indicesEligibleForActivation,
indicesEligibleForActivation: indicesEligibleForActivation.map(({validatorIndex}) => validatorIndex),
indicesToEject,
nextEpochShufflingActiveValidatorIndices,
// to be updated in processEffectiveBalanceUpdates
Expand Down
14 changes: 9 additions & 5 deletions packages/state-transition/src/util/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {bigIntMax} from "@lodestar/utils";
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
import {BeaconStateAllForks} from "..";
import {CachedBeaconStateAllForks} from "../types.js";
import {ReusableListIterator} from "@chainsafe/ssz";

/**
* Return the combined effective balance of the [[indices]].
Expand Down Expand Up @@ -46,7 +47,7 @@ export function decreaseBalance(state: BeaconStateAllForks, index: ValidatorInde
/**
* This data is reused and never gc.
*/
const validators = new Array<phase0.Validator>();
const validators = new ReusableListIterator<phase0.Validator>();

/**
* This method is used to get justified balances from a justified state.
Expand All @@ -68,21 +69,24 @@ export function getEffectiveBalanceIncrementsZeroInactive(
validatorCount
);

validators.length = validatorCount;
justifiedState.validators.getAllReadonlyValues(validators);
validators.reset();
justifiedState.validators.getAllReadonlyValuesIter(validators);
validators.clean();
let i = 0;
let j = 0;
for (let i = 0; i < validatorCount; i++) {
for (const validator of validators) {
if (i === activeIndices[j]) {
// active validator
j++;
if (validators[i].slashed) {
if (validator.slashed) {
// slashed validator
effectiveBalanceIncrementsZeroInactive[i] = 0;
}
} else {
// inactive validator
effectiveBalanceIncrementsZeroInactive[i] = 0;
}
i++;
}

return effectiveBalanceIncrementsZeroInactive;
Expand Down

0 comments on commit 8e09d4c

Please sign in to comment.