@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
108 lines • 4.28 kB
JavaScript
import { SLOTS_PER_EPOCH } from "@lodestar/params";
import { computeStartSlotAtEpoch } from "@lodestar/state-transition";
import { BATCH_SLOT_OFFSET, EPOCHS_PER_BATCH } from "../../constants.js";
import { BatchStatus } from "../batch.js";
/**
* Validates that the status and ordering of batches is valid
* ```
* [AwaitingValidation]* [Processing]? [AwaitingDownload,Downloading,AwaitingProcessing]*
* ```
*/
export function validateBatchesStatus(batches) {
let processing = 0;
let preProcessing = 0;
for (const batch of batches) {
const status = batch.state.status;
switch (status) {
case BatchStatus.AwaitingValidation:
if (processing > 0)
throw Error("AwaitingValidation state found after Processing");
if (preProcessing > 0)
throw Error("AwaitingValidation state found after PreProcessing");
break;
case BatchStatus.Processing:
if (preProcessing > 0)
throw Error("Processing state found after PreProcessing");
if (processing > 0)
throw Error("More than one Processing state found");
processing++;
break;
case BatchStatus.AwaitingDownload:
case BatchStatus.Downloading:
case BatchStatus.AwaitingProcessing:
preProcessing++;
break;
default:
throw Error(`Unknown status: ${status}`);
}
}
}
/**
* Return the next batch to process if any.
* @see validateBatchesStatus for batches state description
*/
export function getNextBatchToProcess(batches) {
for (const batch of batches) {
switch (batch.state.status) {
// If an AwaitingProcessing batch exists it can only be preceeded by AwaitingValidation
case BatchStatus.AwaitingValidation:
break;
case BatchStatus.AwaitingProcessing:
return batch;
// There MUST be no AwaitingProcessing state after AwaitingDownload, Downloading, Processing
case BatchStatus.AwaitingDownload:
case BatchStatus.Downloading:
case BatchStatus.Processing:
return null;
}
}
// Exhausted batches
return null;
}
/**
* Compute the startEpoch of the next batch to be downloaded
*/
export function toBeDownloadedStartEpoch(batches, startEpoch) {
// Note: batches are inserted in ascending `startEpoch` order
const lastBatch = batches.at(-1);
return lastBatch ? lastBatch.startEpoch + EPOCHS_PER_BATCH : startEpoch;
}
export function toArr(map) {
return Array.from(map.values());
}
export function getBatchSlotRange(startEpoch) {
return {
startSlot: computeStartSlotAtEpoch(startEpoch) + BATCH_SLOT_OFFSET,
count: EPOCHS_PER_BATCH * SLOTS_PER_EPOCH,
};
}
/**
* Given a batch's startEpoch, return true if batch does not include slot and is strictly after
* ```
* Batch1 Batch2 Batch3
* ----|--------|-----X--|--------|---
* ```
* - Batch1 = not includes and before = false
* - Batch2 = includes = false
* - Batch3 = not includes and after = true
*/
export function batchStartEpochIsAfterSlot(startEpoch, targetSlot) {
// The range of slots (inclusive) downloaded by a batch
const { startSlot } = getBatchSlotRange(startEpoch);
return startSlot > targetSlot;
}
/**
* Returns true if SyncChain has processed all possible blocks with slot <= target.slot
*/
export function isSyncChainDone(batches, lastEpochWithProcessBlocks, targetSlot) {
// In case of full epochs of skipped slots, lastEpochWithProcessBlocks won't be updated.
// In that case it is assumed that the batches are valid only to be able to mark this SyncChain as done
const lastAwaitingValidation = batches
.reverse()
.find((batch) => batch.state.status === BatchStatus.AwaitingValidation);
if (lastAwaitingValidation) {
return batchStartEpochIsAfterSlot(lastAwaitingValidation.startEpoch + EPOCHS_PER_BATCH, targetSlot);
}
return batchStartEpochIsAfterSlot(lastEpochWithProcessBlocks, targetSlot);
}
//# sourceMappingURL=batches.js.map