Skip to content

Commit

Permalink
feat(core): add era summary to epoch slots calc return value
Browse files Browse the repository at this point in the history
BREAKING CHANGE: remove unused type EpochSlots
  • Loading branch information
iccicci committed Oct 26, 2023
1 parent a00a77d commit 44f2216
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 12 deletions.
33 changes: 27 additions & 6 deletions packages/core/src/util/slotCalc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CustomError } from 'ts-custom-error';
import { EpochNo, NetworkMagics, Slot } from '../Cardano';
import { EraSummary } from '../CardanoNode';
import { NetworkInfoProvider } from '../Provider/NetworkInfoProvider';
import groupBy from 'lodash/groupBy';
import last from 'lodash/last';
import memoize from 'lodash/memoize';
Expand Down Expand Up @@ -119,30 +120,50 @@ export const createSlotEpochInfoCalc = (eraSummaries: EraSummary[]) => {
};

/**
* @returns first slot of the epoch
* The actual implementation, _memoized_ by `epochSlotsCalc` or directly used by `epochSlotsCalcFactory`.
*
* @param epochNo epoch number
* @param eraSummaries era summaries array
* @returns `eraSummary`, `firstSlot` and `lastSlot` of given epoch
*/
export const epochSlotsCalc = memoize((epochNo: EpochNo, eraSummaries: EraSummary[]) => {
const epochSlotsCalcImplementation = (epochNo: EpochNo, eraSummaries: EraSummary[]) => {
let atEpoch = 0;
let atSlot = eraSummaries[0].start.slot;
let eraSummaryIdx = 0;
const maxEraSummaryIdx = eraSummaries.length - 1;

while (atEpoch !== epochNo) {
atSlot += eraSummaries[eraSummaryIdx].parameters.epochLength;
atEpoch++;

if (eraSummaryIdx < maxEraSummaryIdx && atSlot >= eraSummaries[eraSummaryIdx + 1].start.slot) {
eraSummaryIdx++;
}
}

const eraSummary = eraSummaries[eraSummaryIdx];

return {
eraSummary,
firstSlot: Slot(atSlot),
lastSlot: Slot(atSlot + eraSummaries[eraSummaryIdx].parameters.epochLength - 1)
lastSlot: Slot(atSlot + eraSummary.parameters.epochLength - 1)
};
});
};

/**
* @returns first and last slot numbers of the epoch
* @returns `eraSummary`, `firstSlot` and `lastSlot` of given epoch
*/
export type EpochSlots = ReturnType<typeof epochSlotsCalc>;
export const epochSlotsCalc = memoize(epochSlotsCalcImplementation);

/**
* Creates an `epochSlotsCalc` version able to get the epoch summaries from a
* `NetworkInfoProvider` by itself.
*
* @returns the `epochSlotsCalc` function
*/
export const epochSlotsCalcFactory = memoize((provider: NetworkInfoProvider) =>
memoize(async (epochNo: EpochNo) => epochSlotsCalcImplementation(epochNo, await provider.eraSummaries()))
);

/**
* @throws EraSummaryError
Expand Down
18 changes: 12 additions & 6 deletions packages/core/test/util/slotCalc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,36 @@ describe('slotCalc utils', () => {
describe('epochStartCalc', () => {
describe('preprod', () => {
it('correctly computes 1st slot of the 0th epoch', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(0), preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(0), preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[0]);
expect(firstSlot).toBe(0);
expect(lastSlot).toBe(21_599);
});

it('correctly computes 1st slot of some Byron epoch', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(2), preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(2), preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[0]);
expect(firstSlot).toBe(43_200);
expect(lastSlot).toBe(64_799);
});

it('correctly computes 1st slot of last Byron epoch', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(3), preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(3), preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[0]);
expect(firstSlot).toBe(64_800);
expect(lastSlot).toBe(86_399);
});

it('correctly computes 1st slot of first Shelley epoch', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(4), preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(4), preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[1]);
expect(firstSlot).toBe(86_400);
expect(lastSlot).toBe(518_399);
});

it('correctly computes 1st slot of some epoch in the middle of era summaries', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(5), preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(5), preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[2]);
expect(firstSlot).toBe(518_400);
expect(lastSlot).toBe(950_399);
});
Expand All @@ -102,7 +107,8 @@ describe('slotCalc utils', () => {
const epoch = Cardano.EpochNo(20);
const expectedFirstSlot = Cardano.Slot(6_998_400);
const expectedLastSlot = Cardano.Slot(7_430_399);
const { firstSlot, lastSlot } = epochSlotsCalc(epoch, preprodEraSummaries);
const { eraSummary, firstSlot, lastSlot } = epochSlotsCalc(epoch, preprodEraSummaries);
expect(eraSummary).toBe(preprodEraSummaries[5]);
expect(firstSlot).toBe(expectedFirstSlot);
expect(lastSlot).toBe(expectedLastSlot);
const epochSlotCalc = createSlotEpochCalc(preprodEraSummaries);
Expand Down

0 comments on commit 44f2216

Please sign in to comment.