@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
73 lines • 3.52 kB
JavaScript
import { PayloadStatus } from "@lodestar/fork-choice";
import { GENESIS_SLOT } from "@lodestar/params";
import { RespStatus, ResponseError } from "@lodestar/reqresp";
import { computeEpochAtSlot } from "@lodestar/state-transition";
export async function* onExecutionPayloadEnvelopesByRange(request, chain, db) {
const { startSlot, count } = validateExecutionPayloadEnvelopesByRangeRequest(chain.config, request);
const endSlot = startSlot + count;
if (startSlot < chain.earliestAvailableSlot) {
return;
}
const finalized = db.executionPayloadEnvelopeArchive;
const finalizedSlot = chain.forkChoice.getFinalizedCheckpointSlot();
// The current finalized block's envelope is still in the hot db; archive migration happens
// in the next finalization run (see migrateExecutionPayloadEnvelopesFromHotToColdDb).
const archiveMaxSlot = finalizedSlot - 1;
// Finalized range of envelopes
if (startSlot <= archiveMaxSlot) {
for await (const { key, value: envelopeBytes } of finalized.binaryEntriesStream({
gte: startSlot,
lt: Math.min(endSlot, archiveMaxSlot + 1),
})) {
const slot = finalized.decodeKey(key);
yield {
data: envelopeBytes,
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(slot)),
};
}
}
// Non-finalized range of envelopes
if (endSlot > archiveMaxSlot) {
const headBlock = chain.forkChoice.getHead();
const headRoot = headBlock.blockRoot;
const headChain = chain.forkChoice.getAllAncestorBlocks(headRoot, headBlock.payloadStatus);
// Iterate head chain with ascending block numbers
for (let i = headChain.length - 1; i >= 0; i--) {
const block = headChain[i];
if (block.slot > archiveMaxSlot && block.slot >= startSlot && block.slot < endSlot) {
// Skip EMPTY blocks
if (block.payloadStatus !== PayloadStatus.FULL) {
continue;
}
const envelopeBytes = await chain.getSerializedExecutionPayloadEnvelope(block.slot, block.blockRoot);
if (!envelopeBytes) {
throw new ResponseError(RespStatus.SERVER_ERROR, `No envelope for root ${block.blockRoot} slot ${block.slot}, startSlot=${startSlot} endSlot=${endSlot} finalizedSlot=${finalizedSlot}`);
}
yield {
data: envelopeBytes,
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(block.slot)),
};
}
else if (block.slot >= endSlot) {
break;
}
}
}
}
export function validateExecutionPayloadEnvelopesByRangeRequest(config, request) {
const { startSlot } = request;
let { count } = request;
if (count < 1) {
throw new ResponseError(RespStatus.INVALID_REQUEST, "count < 1");
}
if (startSlot < GENESIS_SLOT) {
throw new ResponseError(RespStatus.INVALID_REQUEST, "startSlot < genesis");
}
// The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
// Archival nodes may still serve older retained payloads to allow genesis sync.
if (count > config.MAX_REQUEST_BLOCKS_DENEB) {
count = config.MAX_REQUEST_BLOCKS_DENEB;
}
return { startSlot, count };
}
//# sourceMappingURL=executionPayloadEnvelopesByRange.js.map