mirror of
https://github.com/ChainSafe/lodestar.git
synced 2026-01-10 16:18:17 -05:00
feat: validate blob schedule on startup (#7942)
We should validate the correctness of blob schedule in addition to its format when parsing it. Relevant spec ethereum/consensus-specs#4370 --------- Co-authored-by: Nico Flaig <nflaig@protonmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import {fromHex, toHex} from "@lodestar/utils";
|
||||
import {validateBlobSchedule} from "../utils/validateBlobSchedule.js";
|
||||
import {
|
||||
BlobSchedule,
|
||||
BlobScheduleEntry,
|
||||
@@ -168,5 +169,7 @@ export function deserializeBlobSchedule(input: unknown): BlobSchedule {
|
||||
return out;
|
||||
});
|
||||
|
||||
validateBlobSchedule(blobSchedule);
|
||||
|
||||
return blobSchedule;
|
||||
}
|
||||
|
||||
@@ -149,12 +149,7 @@ export function createForkConfig(config: ChainConfig): ForkConfig {
|
||||
}
|
||||
|
||||
// Sort by epoch in descending order to find the latest applicable value
|
||||
const blobSchedule = [...config.BLOB_SCHEDULE].sort((a, b) => {
|
||||
if (a.EPOCH !== b.EPOCH) {
|
||||
return b.EPOCH - a.EPOCH;
|
||||
}
|
||||
return b.MAX_BLOBS_PER_BLOCK - a.MAX_BLOBS_PER_BLOCK;
|
||||
});
|
||||
const blobSchedule = [...config.BLOB_SCHEDULE].sort((a, b) => b.EPOCH - a.EPOCH);
|
||||
|
||||
for (const entry of blobSchedule) {
|
||||
if (epoch >= entry.EPOCH) {
|
||||
|
||||
32
packages/config/src/utils/validateBlobSchedule.ts
Normal file
32
packages/config/src/utils/validateBlobSchedule.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import {MAX_BLOB_COMMITMENTS_PER_BLOCK} from "@lodestar/params";
|
||||
import {BlobSchedule} from "../chainConfig/types.js";
|
||||
|
||||
export function validateBlobSchedule(blobSchedule: BlobSchedule): void {
|
||||
if (blobSchedule.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let previousEpoch: number | undefined;
|
||||
|
||||
for (const [i, entry] of blobSchedule.entries()) {
|
||||
if (previousEpoch !== undefined) {
|
||||
if (entry.EPOCH < previousEpoch) {
|
||||
throw Error(
|
||||
`Invalid BLOB_SCHEDULE expected entries to be sorted by EPOCH in ascending order, ${entry.EPOCH} < ${previousEpoch} at index ${i}`
|
||||
);
|
||||
}
|
||||
if (entry.EPOCH === previousEpoch) {
|
||||
throw Error(
|
||||
`Invalid BLOB_SCHEDULE[${i}] entry with the same epoch value ${entry.EPOCH} as previous BLOB_SCHEDULE[${i - 1}] entry`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (entry.MAX_BLOBS_PER_BLOCK > MAX_BLOB_COMMITMENTS_PER_BLOCK) {
|
||||
throw Error(
|
||||
`Invalid BLOB_SCHEDULE[${i}].MAX_BLOBS_PER_BLOCK value ${entry.MAX_BLOBS_PER_BLOCK} exceeds limit ${MAX_BLOB_COMMITMENTS_PER_BLOCK}`
|
||||
);
|
||||
}
|
||||
|
||||
previousEpoch = entry.EPOCH;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import {MAX_BLOB_COMMITMENTS_PER_BLOCK} from "@lodestar/params";
|
||||
import {describe, expect, it} from "vitest";
|
||||
import {chainConfig} from "../../src/default.js";
|
||||
import {BlobSchedule, chainConfigFromJson, chainConfigToJson} from "../../src/index.js";
|
||||
@@ -13,9 +14,8 @@ describe("chainConfig JSON", () => {
|
||||
it("Custom blob schedule", () => {
|
||||
const blobSchedule: BlobSchedule = [
|
||||
{EPOCH: 0, MAX_BLOBS_PER_BLOCK: 10},
|
||||
{EPOCH: 10, MAX_BLOBS_PER_BLOCK: Infinity},
|
||||
{EPOCH: 10, MAX_BLOBS_PER_BLOCK: 15},
|
||||
{EPOCH: Infinity, MAX_BLOBS_PER_BLOCK: 20},
|
||||
{EPOCH: Infinity, MAX_BLOBS_PER_BLOCK: Infinity},
|
||||
];
|
||||
const configWithCustomBlobSchedule = {...chainConfig, BLOB_SCHEDULE: blobSchedule};
|
||||
|
||||
@@ -24,4 +24,41 @@ describe("chainConfig JSON", () => {
|
||||
|
||||
expect(chainConfigRes).toEqual(configWithCustomBlobSchedule);
|
||||
});
|
||||
|
||||
it("Blob schedule max blobs exceeds limit", () => {
|
||||
const blobSchedule: BlobSchedule = [{EPOCH: 0, MAX_BLOBS_PER_BLOCK: MAX_BLOB_COMMITMENTS_PER_BLOCK + 1}];
|
||||
const configWithCustomBlobSchedule = {...chainConfig, BLOB_SCHEDULE: blobSchedule};
|
||||
|
||||
const json = chainConfigToJson(configWithCustomBlobSchedule);
|
||||
|
||||
expect(() => chainConfigFromJson(json)).toThrow();
|
||||
});
|
||||
|
||||
it("Blob schedule in wrong order", () => {
|
||||
const blobSchedule: BlobSchedule = [
|
||||
{EPOCH: 20, MAX_BLOBS_PER_BLOCK: 20},
|
||||
{EPOCH: 10, MAX_BLOBS_PER_BLOCK: 15},
|
||||
{EPOCH: 0, MAX_BLOBS_PER_BLOCK: 10},
|
||||
];
|
||||
|
||||
const configWithCustomBlobSchedule = {...chainConfig, BLOB_SCHEDULE: blobSchedule};
|
||||
|
||||
const json = chainConfigToJson(configWithCustomBlobSchedule);
|
||||
|
||||
expect(() => chainConfigFromJson(json)).toThrow();
|
||||
});
|
||||
|
||||
it("Blob schedule entries with the same epoch value", () => {
|
||||
const blobSchedule: BlobSchedule = [
|
||||
{EPOCH: 0, MAX_BLOBS_PER_BLOCK: 10},
|
||||
{EPOCH: 10, MAX_BLOBS_PER_BLOCK: 15},
|
||||
{EPOCH: 10, MAX_BLOBS_PER_BLOCK: 20},
|
||||
];
|
||||
|
||||
const configWithCustomBlobSchedule = {...chainConfig, BLOB_SCHEDULE: blobSchedule};
|
||||
|
||||
const json = chainConfigToJson(configWithCustomBlobSchedule);
|
||||
|
||||
expect(() => chainConfigFromJson(json)).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user