Skip to content

Commit

Permalink
Add more test cases to diff archives
Browse files Browse the repository at this point in the history
  • Loading branch information
nazarhussain committed Nov 4, 2024
1 parent 8d62659 commit 01e30ad
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
28 changes: 18 additions & 10 deletions packages/beacon-node/src/chain/historicalState/utils/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,30 @@ export async function getDiffStateArchive(
return {layers: {diffSlots, snapshotSlot: availableSnapshotSlot}, stateArchive: snapshotArchive};
}

// Get all diffs except the first one which was a snapshot layer
const diffArchives = await Promise.all(
diffSlots.map((s) => measure(metrics?.loadDiffStateTime, () => db.hierarchicalStateArchiveRepository.get(s)))
);
// In cases when snapshot is taken during the checkpoint sync and is at higher slot than expected
const applicableDiffs = diffSlots.filter((s) => s > availableSnapshotSlot);

const nonEmptyDiffs = diffArchives.filter(Boolean) as StateArchive[];
// Get all diffs except the first one which was a snapshot layer
const diffArchives = (
await Promise.all(
applicableDiffs.map((s) =>
measure(metrics?.loadDiffStateTime, () => db.hierarchicalStateArchiveRepository.get(s))
)
)
).filter(Boolean) as StateArchive[];

if (nonEmptyDiffs.length < diffSlots.length) {
logger?.warn("Missing some diff states", {
// If we apply some diff with missing one, it will not fail rather result in wrong state computation
if (diffArchives.length > 0 && diffArchives.length < applicableDiffs.length) {
logger?.error("Missing some diff states", {
epoch,
slot,
snapshotSlot: expectedSnapshotSlot,
diffPath: diffSlots.join(","),
availableDiffs: nonEmptyDiffs.map((d) => d.slot).join(","),
availableDiffs: diffArchives.map((d) => d.slot).join(","),
});
metrics?.regenErrorCount.inc({reason: RegenErrorType.loadState});

return {layers: {snapshotSlot: availableSnapshotSlot, diffSlots}, stateArchive: null};
}

try {
Expand All @@ -81,12 +89,12 @@ export async function getDiffStateArchive(
slot,
snapshotSlot: expectedSnapshotSlot,
diffPath: diffSlots.join(","),
availableDiffs: nonEmptyDiffs.map((d) => d.slot).join(","),
availableDiffs: diffArchives.map((d) => d.slot).join(","),
});

let activeStateArchive = snapshotArchive;

for (const intermediateStateArchive of nonEmptyDiffs) {
for (const intermediateStateArchive of diffArchives) {
logger?.verbose("Applying state diff", {
activeSlot: intermediateStateArchive.slot,
activeStateSize: formatBytes(StateArchiveSSZType.serialize(activeStateArchive).byteLength),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,54 @@ describe("historicalState/util", () => {
});
expect(codec.apply).not.toBeCalled();
});

it("should fail if any intermediate diff is missing", async () => {
const slot = computeStartSlotAtEpoch(70) + 1;
const layers = hierarchicalLayers.getArchiveLayers(slot);
const archives = generateStateArchives(layers);

expect(layers.diffSlots.length).greaterThan(1);

when(db.hierarchicalStateArchiveRepository.get)
.calledWith(layers.snapshotSlot)
.thenResolve(archives.states[layers.snapshotSlot]);

for (const diffSlot of layers.diffSlots) {
when(db.hierarchicalStateArchiveRepository.get).calledWith(diffSlot).thenResolve(archives.diffs[diffSlot]);
}
when(db.hierarchicalStateArchiveRepository.get).calledWith(layers.diffSlots[0]).thenResolve(null);

await expect(getDiffStateArchive(slot, {db, logger, hierarchicalLayers, codec})).resolves.toEqual({
stateArchive: null,
layers,
});
expect(codec.apply).not.toBeCalled();
});

it("should fail if some final diff is missing", async () => {
const slot = computeStartSlotAtEpoch(70) + 1;
const layers = hierarchicalLayers.getArchiveLayers(slot);
const archives = generateStateArchives(layers);

expect(layers.diffSlots).not.toHaveLength(0);

when(db.hierarchicalStateArchiveRepository.get)
.calledWith(layers.snapshotSlot)
.thenResolve(archives.states[layers.snapshotSlot]);

for (const diffSlot of layers.diffSlots) {
when(db.hierarchicalStateArchiveRepository.get).calledWith(diffSlot).thenResolve(archives.diffs[diffSlot]);
}
when(db.hierarchicalStateArchiveRepository.get)
.calledWith(layers.diffSlots[layers.diffSlots.length - 1])
.thenResolve(null);

await expect(getDiffStateArchive(slot, {db, logger, hierarchicalLayers, codec})).resolves.toEqual({
stateArchive: null,
layers,
});
expect(codec.apply).not.toBeCalled();
});
});
});

Expand Down

0 comments on commit 01e30ad

Please sign in to comment.