Skip to content

Commit

Permalink
fix: reuse Buffer instance (#7016)
Browse files Browse the repository at this point in the history
* fix: improve message id to string conversion

* fix: use shared Buffers for sszBytes util

* feat: implement toRootHex()

* fix: lint and check-types

* Fix type checks

* Add comment to vitest config

* Update packages/utils/src/bytes.ts

---------

Co-authored-by: Nico Flaig <[email protected]>
Co-authored-by: Cayman <[email protected]>
  • Loading branch information
3 people committed Aug 13, 2024
1 parent 9c62011 commit 44b2156
Show file tree
Hide file tree
Showing 40 changed files with 268 additions and 181 deletions.
4 changes: 2 additions & 2 deletions packages/beacon-node/src/chain/balancesCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "@lodestar/state-transition";
import {CheckpointWithHex} from "@lodestar/fork-choice";
import {Epoch, RootHex} from "@lodestar/types";
import {toHexString} from "@lodestar/utils";
import {toRootHex} from "@lodestar/utils";

/** The number of validator balance sets that are cached within `CheckpointBalancesCache`. */
const MAX_BALANCE_CACHE_SIZE = 4;
Expand All @@ -33,7 +33,7 @@ export class CheckpointBalancesCache {
const epoch = state.epochCtx.epoch;
const epochBoundarySlot = computeStartSlotAtEpoch(epoch);
const epochBoundaryRoot =
epochBoundarySlot === state.slot ? blockRootHex : toHexString(getBlockRootAtSlot(state, epochBoundarySlot));
epochBoundarySlot === state.slot ? blockRootHex : toRootHex(getBlockRootAtSlot(state, epochBoundarySlot));

const index = this.items.findIndex((item) => item.epoch === epoch && item.rootHex == epochBoundaryRoot);
if (index === -1) {
Expand Down
10 changes: 5 additions & 5 deletions packages/beacon-node/src/chain/blocks/importBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "@lodestar/state-transition";
import {routes} from "@lodestar/api";
import {ForkChoiceError, ForkChoiceErrorCode, EpochDifference, AncestorStatus} from "@lodestar/fork-choice";
import {isErrorAborted} from "@lodestar/utils";
import {isErrorAborted, toRootHex} from "@lodestar/utils";
import {ZERO_HASH_HEX} from "../../constants/index.js";
import {toCheckpointHex} from "../stateCache/index.js";
import {isOptimisticBlock} from "../../util/forkChoice.js";
Expand Down Expand Up @@ -62,7 +62,7 @@ export async function importBlock(
const {block, source} = blockInput;
const {slot: blockSlot} = block.message;
const blockRoot = this.config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message);
const blockRootHex = toHexString(blockRoot);
const blockRootHex = toRootHex(blockRoot);
const currentEpoch = computeEpochAtSlot(this.forkChoice.getTime());
const blockEpoch = computeEpochAtSlot(blockSlot);
const parentEpoch = computeEpochAtSlot(parentBlockSlot);
Expand Down Expand Up @@ -123,7 +123,7 @@ export async function importBlock(
const indexedAttestation = postState.epochCtx.getIndexedAttestation(attestation);
const {target, beaconBlockRoot} = attestation.data;

const attDataRoot = toHexString(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data));
const attDataRoot = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(indexedAttestation.data));
this.seenAggregatedAttestations.add(
target.epoch,
attDataRoot,
Expand Down Expand Up @@ -371,9 +371,9 @@ export async function importBlock(
const preFinalizedEpoch = parentBlockSummary.finalizedEpoch;
if (finalizedEpoch > preFinalizedEpoch) {
this.emitter.emit(routes.events.EventType.finalizedCheckpoint, {
block: toHexString(finalizedCheckpoint.root),
block: toRootHex(finalizedCheckpoint.root),
epoch: finalizedCheckpoint.epoch,
state: toHexString(checkpointState.hashTreeRoot()),
state: toRootHex(checkpointState.hashTreeRoot()),
executionOptimistic: false,
});
this.logger.verbose("Checkpoint finalized", toCheckpointHex(finalizedCheckpoint));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
import {ChainForkConfig} from "@lodestar/config";
import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
import {Slot} from "@lodestar/types";
import {toHexString} from "@lodestar/utils";
import {toHexString, toRootHex} from "@lodestar/utils";
import {IClock} from "../../util/clock.js";
import {BlockError, BlockErrorCode} from "../errors/index.js";
import {BlockInput, ImportBlockOpts} from "./types.js";
Expand Down Expand Up @@ -67,7 +67,7 @@ export function verifyBlocksSanityChecks(
parentBlockSlot = relevantBlocks[relevantBlocks.length - 1].block.message.slot;
} else {
// When importing a block segment, only the first NON-IGNORED block must be known to the fork-choice.
const parentRoot = toHexString(block.message.parentRoot);
const parentRoot = toRootHex(block.message.parentRoot);
parentBlock = chain.forkChoice.getBlockHex(parentRoot);
if (!parentBlock) {
throw new BlockError(block, {code: BlockErrorCode.PARENT_UNKNOWN, parentRoot});
Expand Down
18 changes: 9 additions & 9 deletions packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import path from "node:path";
import {CompositeTypeAny, fromHexString, TreeView, Type, toHexString} from "@chainsafe/ssz";
import {CompositeTypeAny, fromHexString, TreeView, Type} from "@chainsafe/ssz";
import {
BeaconStateAllForks,
CachedBeaconStateAllForks,
Expand Down Expand Up @@ -35,7 +35,7 @@ import {
} from "@lodestar/types";
import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
import {ProcessShutdownCallback} from "@lodestar/validator";
import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils";
import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex, toRootHex} from "@lodestar/utils";
import {ForkSeq, GENESIS_SLOT, SLOTS_PER_EPOCH} from "@lodestar/params";

import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js";
Expand Down Expand Up @@ -592,7 +592,7 @@ export class BeaconChain implements IBeaconChain {
async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody> {
const {slot, parentBlockRoot} = blockAttributes;
const state = await this.regen.getBlockSlotState(
toHexString(parentBlockRoot),
toRootHex(parentBlockRoot),
slot,
{dontTransferCache: true},
RegenCaller.produceBlock
Expand Down Expand Up @@ -641,7 +641,7 @@ export class BeaconChain implements IBeaconChain {
shouldOverrideBuilder?: boolean;
}> {
const state = await this.regen.getBlockSlotState(
toHexString(parentBlockRoot),
toRootHex(parentBlockRoot),
slot,
{dontTransferCache: true},
RegenCaller.produceBlock
Expand Down Expand Up @@ -673,7 +673,7 @@ export class BeaconChain implements IBeaconChain {
: this.config.getExecutionForkTypes(slot).BlindedBeaconBlockBody.hashTreeRoot(body as BlindedBeaconBlockBody);
this.logger.debug("Computing block post state from the produced body", {
slot,
bodyRoot: toHexString(bodyRoot),
bodyRoot: toRootHex(bodyRoot),
blockType,
});

Expand Down Expand Up @@ -1152,10 +1152,10 @@ export class BeaconChain implements IBeaconChain {
const preState = this.regen.getPreStateSync(block);

if (preState === null) {
throw Error(`Pre-state is unavailable given block's parent root ${toHexString(block.parentRoot)}`);
throw Error(`Pre-state is unavailable given block's parent root ${toRootHex(block.parentRoot)}`);
}

const postState = this.regen.getStateSync(toHexString(block.stateRoot)) ?? undefined;
const postState = this.regen.getStateSync(toRootHex(block.stateRoot)) ?? undefined;

return computeBlockRewards(block, preState.clone(), postState?.clone());
}
Expand All @@ -1173,7 +1173,7 @@ export class BeaconChain implements IBeaconChain {
}

const {executionOptimistic, finalized} = stateResult;
const stateRoot = toHexString(stateResult.state.hashTreeRoot());
const stateRoot = toRootHex(stateResult.state.hashTreeRoot());

const cachedState = this.regen.getStateSync(stateRoot);

Expand All @@ -1193,7 +1193,7 @@ export class BeaconChain implements IBeaconChain {
const preState = this.regen.getPreStateSync(block);

if (preState === null) {
throw Error(`Pre-state is unavailable given block's parent root ${toHexString(block.parentRoot)}`);
throw Error(`Pre-state is unavailable given block's parent root ${toRootHex(block.parentRoot)}`);
}

return computeSyncCommitteeRewards(block, preState.clone(), validatorIds);
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/chain/errors/attestationError.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {toHexString} from "@chainsafe/ssz";
import {Epoch, Slot, ValidatorIndex, RootHex} from "@lodestar/types";
import {toRootHex} from "@lodestar/utils";
import {GossipActionError} from "./gossipValidation.js";

export enum AttestationErrorCode {
Expand Down Expand Up @@ -167,7 +167,7 @@ export class AttestationError extends GossipActionError<AttestationErrorType> {
const type = this.type;
switch (type.code) {
case AttestationErrorCode.UNKNOWN_TARGET_ROOT:
return {code: type.code, root: toHexString(type.root)};
return {code: type.code, root: toRootHex(type.root)};
case AttestationErrorCode.MISSING_STATE_TO_VERIFY_ATTESTATION:
// TODO: The stack trace gets lost here
return {code: type.code, error: type.error.message};
Expand Down
7 changes: 3 additions & 4 deletions packages/beacon-node/src/chain/errors/blockError.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {toHexString} from "@chainsafe/ssz";
import {RootHex, SignedBeaconBlock, Slot, ValidatorIndex} from "@lodestar/types";
import {LodestarError} from "@lodestar/utils";
import {LodestarError, toRootHex} from "@lodestar/utils";
import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
import {ExecutionPayloadStatus} from "../../execution/engine/interface.js";
import {QueueErrorCode} from "../../util/queue/index.js";
Expand Down Expand Up @@ -151,8 +150,8 @@ export function renderBlockErrorType(type: BlockErrorType): Record<string, strin
return {
code: type.code,
slot: type.postState.slot,
root: toHexString(type.root),
expectedRoot: toHexString(type.expectedRoot),
root: toRootHex(type.root),
expectedRoot: toRootHex(type.expectedRoot),
};

default:
Expand Down
16 changes: 8 additions & 8 deletions packages/beacon-node/src/chain/forkChoice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
isMergeTransitionComplete,
} from "@lodestar/state-transition";

import {Logger} from "@lodestar/utils";
import {Logger, toRootHex} from "@lodestar/utils";
import {computeAnchorCheckpoint} from "../initState.js";
import {ChainEventEmitter} from "../emitter.js";
import {ChainEvent} from "../emitter.js";
Expand Down Expand Up @@ -75,19 +75,19 @@ export function initializeForkChoice(
ProtoArray.initialize(
{
slot: blockHeader.slot,
parentRoot: toHexString(blockHeader.parentRoot),
stateRoot: toHexString(blockHeader.stateRoot),
blockRoot: toHexString(checkpoint.root),
parentRoot: toRootHex(blockHeader.parentRoot),
stateRoot: toRootHex(blockHeader.stateRoot),
blockRoot: toRootHex(checkpoint.root),
timeliness: true, // Optimisitcally assume is timely

justifiedEpoch: justifiedCheckpoint.epoch,
justifiedRoot: toHexString(justifiedCheckpoint.root),
justifiedRoot: toRootHex(justifiedCheckpoint.root),
finalizedEpoch: finalizedCheckpoint.epoch,
finalizedRoot: toHexString(finalizedCheckpoint.root),
finalizedRoot: toRootHex(finalizedCheckpoint.root),
unrealizedJustifiedEpoch: justifiedCheckpoint.epoch,
unrealizedJustifiedRoot: toHexString(justifiedCheckpoint.root),
unrealizedJustifiedRoot: toRootHex(justifiedCheckpoint.root),
unrealizedFinalizedEpoch: finalizedCheckpoint.epoch,
unrealizedFinalizedRoot: toHexString(finalizedCheckpoint.root),
unrealizedFinalizedRoot: toRootHex(finalizedCheckpoint.root),

...(isExecutionStateType(state) && isMergeTransitionComplete(state)
? {
Expand Down
13 changes: 6 additions & 7 deletions packages/beacon-node/src/chain/initState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {toHexString} from "@chainsafe/ssz";
import {
blockToHeader,
computeEpochAtSlot,
Expand All @@ -9,7 +8,7 @@ import {
} from "@lodestar/state-transition";
import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types";
import {ChainForkConfig} from "@lodestar/config";
import {Logger, toHex} from "@lodestar/utils";
import {Logger, toHex, toRootHex} from "@lodestar/utils";
import {GENESIS_SLOT, ZERO_HASH} from "../constants/index.js";
import {IBeaconDb} from "../db/index.js";
import {Eth1Provider} from "../eth1/index.js";
Expand Down Expand Up @@ -103,8 +102,8 @@ export async function initStateFromEth1({
const blockRoot = types.BeaconBlock.hashTreeRoot(genesisBlock.message);

logger.info("Initializing genesis state", {
stateRoot: toHexString(stateRoot),
blockRoot: toHexString(blockRoot),
stateRoot: toRootHex(stateRoot),
blockRoot: toRootHex(blockRoot),
validatorCount: genesisResult.state.validators.length,
});

Expand Down Expand Up @@ -146,7 +145,7 @@ export async function initStateFromDb(
logger.info("Initializing beacon state from db", {
slot: state.slot,
epoch: computeEpochAtSlot(state.slot),
stateRoot: toHexString(state.hashTreeRoot()),
stateRoot: toRootHex(state.hashTreeRoot()),
});

return state;
Expand Down Expand Up @@ -179,14 +178,14 @@ export async function initStateFromAnchorState(
logger.info(`Initializing beacon from a valid ${stateInfo} state`, {
slot: anchorState.slot,
epoch: computeEpochAtSlot(anchorState.slot),
stateRoot: toHexString(anchorState.hashTreeRoot()),
stateRoot: toRootHex(anchorState.hashTreeRoot()),
isWithinWeakSubjectivityPeriod,
});
} else {
logger.warn(`Initializing from a stale ${stateInfo} state vulnerable to long range attacks`, {
slot: anchorState.slot,
epoch: computeEpochAtSlot(anchorState.slot),
stateRoot: toHexString(anchorState.hashTreeRoot()),
stateRoot: toRootHex(anchorState.hashTreeRoot()),
isWithinWeakSubjectivityPeriod,
});
logger.warn("Checkpoint sync recommended, please use --help to see checkpoint sync options");
Expand Down
20 changes: 10 additions & 10 deletions packages/beacon-node/src/chain/lightClient/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {BitArray, CompositeViewDU, toHexString} from "@chainsafe/ssz";
import {BitArray, CompositeViewDU} from "@chainsafe/ssz";
import {
altair,
BeaconBlock,
Expand Down Expand Up @@ -31,7 +31,7 @@ import {
LightClientUpdateSummary,
upgradeLightClientHeader,
} from "@lodestar/light-client/spec";
import {Logger, MapDef, pruneSetToMax} from "@lodestar/utils";
import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils";
import {routes} from "@lodestar/api";
import {
MIN_SYNC_COMMITTEE_PARTICIPANTS,
Expand Down Expand Up @@ -292,7 +292,7 @@ export class LightClientServer {
if (!syncCommitteeWitness) {
throw new LightClientServerError(
{code: LightClientServerErrorCode.RESOURCE_UNAVAILABLE},
`syncCommitteeWitness not available ${toHexString(blockRoot)}`
`syncCommitteeWitness not available ${toRootHex(blockRoot)}`
);
}

Expand Down Expand Up @@ -352,7 +352,7 @@ export class LightClientServer {
if (!syncCommitteeWitness) {
throw new LightClientServerError(
{code: LightClientServerErrorCode.RESOURCE_UNAVAILABLE},
`syncCommitteeWitness not available ${toHexString(blockRoot)} period ${period}`
`syncCommitteeWitness not available ${toRootHex(blockRoot)} period ${period}`
);
}

Expand Down Expand Up @@ -391,7 +391,7 @@ export class LightClientServer {
const header = blockToLightClientHeader(this.config.getForkName(blockSlot), block);

const blockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(header.beacon);
const blockRootHex = toHexString(blockRoot);
const blockRootHex = toRootHex(blockRoot);

const syncCommitteeWitness = getSyncCommitteesWitness(postState);

Expand All @@ -410,7 +410,7 @@ export class LightClientServer {
const period = computeSyncPeriodAtSlot(blockSlot);
if (parentBlockPeriod < period) {
// If the parentBlock is in a previous epoch it must be the dependentRoot of this epoch transition
const dependentRoot = toHexString(block.parentRoot);
const dependentRoot = toRootHex(block.parentRoot);
const periodDependentRoots = this.knownSyncCommittee.getOrDefault(period);
if (!periodDependentRoots.has(dependentRoot)) {
periodDependentRoots.add(dependentRoot);
Expand Down Expand Up @@ -486,7 +486,7 @@ export class LightClientServer {
): Promise<void> {
this.metrics?.lightclientServer.onSyncAggregate.inc({event: "processed"});

const signedBlockRootHex = toHexString(signedBlockRoot);
const signedBlockRootHex = toRootHex(signedBlockRoot);
const attestedData = this.prevHeadData.get(signedBlockRootHex);
if (!attestedData) {
// Log cacheSize since at start this.prevHeadData will be empty
Expand Down Expand Up @@ -574,7 +574,7 @@ export class LightClientServer {
} catch (e) {
this.logger.error(
"Error updating best LightClientUpdate",
{syncPeriod, slot: attestedHeader.beacon.slot, blockRoot: toHexString(attestedData.blockRoot)},
{syncPeriod, slot: attestedHeader.beacon.slot, blockRoot: toRootHex(attestedData.blockRoot)},
e as Error
);
}
Expand Down Expand Up @@ -619,7 +619,7 @@ export class LightClientServer {

const syncCommitteeWitness = await this.db.syncCommitteeWitness.get(attestedData.blockRoot);
if (!syncCommitteeWitness) {
throw Error(`syncCommitteeWitness not available at ${toHexString(attestedData.blockRoot)}`);
throw Error(`syncCommitteeWitness not available at ${toRootHex(attestedData.blockRoot)}`);
}
const nextSyncCommittee = await this.db.syncCommittee.get(syncCommitteeWitness.nextSyncCommitteeRoot);
if (!nextSyncCommittee) {
Expand Down Expand Up @@ -697,7 +697,7 @@ export class LightClientServer {
* Get finalized header from db. Keeps a small in-memory cache to speed up most of the lookups
*/
private async getFinalizedHeader(finalizedBlockRoot: Uint8Array): Promise<LightClientHeader | null> {
const finalizedBlockRootHex = toHexString(finalizedBlockRoot);
const finalizedBlockRootHex = toRootHex(finalizedBlockRoot);
const cachedFinalizedHeader = this.checkpointHeaders.get(finalizedBlockRootHex);
if (cachedFinalizedHeader) {
return cachedFinalizedHeader;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {toHexString} from "@chainsafe/ssz";
import {aggregateSignatures} from "@chainsafe/blst";
import {ForkName, ForkSeq, MAX_ATTESTATIONS, MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params";
import {phase0, Epoch, Slot, ssz, ValidatorIndex, RootHex} from "@lodestar/types";
Expand All @@ -11,7 +10,7 @@ import {
getBlockRootAtSlot,
} from "@lodestar/state-transition";
import {IForkChoice, EpochDifference} from "@lodestar/fork-choice";
import {toHex, MapDef} from "@lodestar/utils";
import {toHex, MapDef, toRootHex} from "@lodestar/utils";
import {intersectUint8Arrays, IntersectResult} from "../../util/bitArray.js";
import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js";
import {InsertOutcome} from "./types.js";
Expand Down Expand Up @@ -573,7 +572,7 @@ function isValidShuffling(
// Otherwise the shuffling is determined by the block at the end of the target epoch
// minus the shuffling lookahead (usually 2). We call this the "pivot".
const pivotSlot = computeStartSlotAtEpoch(targetEpoch - 1) - 1;
const stateDependentRoot = toHexString(getBlockRootAtSlot(state, pivotSlot));
const stateDependentRoot = toRootHex(getBlockRootAtSlot(state, pivotSlot));

// Use fork choice's view of the block DAG to quickly evaluate whether the attestation's
// pivot block is the same as the current state's pivot block. If it is, then the
Expand Down
3 changes: 2 additions & 1 deletion packages/beacon-node/src/chain/opPools/opPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ForkSeq,
} from "@lodestar/params";
import {Epoch, phase0, capella, ssz, ValidatorIndex, SignedBeaconBlock} from "@lodestar/types";
import {toRootHex} from "@lodestar/utils";
import {IBeaconDb} from "../../db/index.js";
import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js";
import {BlockType} from "../interface.js";
Expand Down Expand Up @@ -135,7 +136,7 @@ export class OpPool {
if (!rootHash) rootHash = ssz.phase0.AttesterSlashing.hashTreeRoot(attesterSlashing);
// TODO: Do once and cache attached to the AttesterSlashing object
const intersectingIndices = getAttesterSlashableIndices(attesterSlashing);
this.attesterSlashings.set(toHexString(rootHash), {
this.attesterSlashings.set(toRootHex(rootHash), {
attesterSlashing,
intersectingIndices,
});
Expand Down
Loading

0 comments on commit 44b2156

Please sign in to comment.