Skip to content

Commit

Permalink
feat(core): add createEpochSlotsCalc that computes 1st and last slot …
Browse files Browse the repository at this point in the history
…# of the epoch
  • Loading branch information
mkazlauskas committed Mar 19, 2023
1 parent a894dd7 commit 266b951
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 2 deletions.
26 changes: 26 additions & 0 deletions packages/core/src/util/slotCalc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,32 @@ export const createSlotEpochInfoCalc = (eraSummaries: EraSummary[]) => {
};
};

/**
* @returns first slot of the epoch
*/
export const epochSlotsCalc = memoize((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++;
}
}
return {
firstSlot: Slot(atSlot),
lastSlot: Slot(atSlot + eraSummaries[eraSummaryIdx].parameters.epochLength - 1)
};
});

/**
* @returns first and last slot numbers of the epoch
*/
export type EpochSlots = ReturnType<typeof epochSlotsCalc>;

/**
* @throws EraSummaryError
* @returns {Date} date of the slot
Expand Down
83 changes: 81 additions & 2 deletions packages/core/test/util/slotCalc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
SlotTimeCalc,
createSlotEpochCalc,
createSlotEpochInfoCalc,
createSlotTimeCalc
createSlotTimeCalc,
epochSlotsCalc
} from '../../src';

import merge from 'lodash/merge';
Expand All @@ -34,7 +35,85 @@ export const testnetEraSummaries: EraSummary[] = [
}
];

// Valid at 2023-03
const preprodEraSummaries: EraSummary[] = [
{
parameters: { epochLength: 21_600, slotLength: Milliseconds(20_000) },
start: { slot: 0, time: new Date('2022-06-01T00:00:00.000Z') }
},
{
parameters: { epochLength: 432_000, slotLength: Milliseconds(1000) },
start: { slot: 86_400, time: new Date('2022-06-21T00:00:00.000Z') }
},
{
parameters: { epochLength: 432_000, slotLength: Milliseconds(1000) },
start: { slot: 518_400, time: new Date('2022-06-26T00:00:00.000Z') }
},
{
parameters: { epochLength: 432_000, slotLength: Milliseconds(1000) },
start: { slot: 950_400, time: new Date('2022-07-01T00:00:00.000Z') }
},
{
parameters: { epochLength: 432_000, slotLength: Milliseconds(1000) },
start: { slot: 1_382_400, time: new Date('2022-07-06T00:00:00.000Z') }
},
{
parameters: { epochLength: 432_000, slotLength: Milliseconds(1000) },
start: { slot: 3_542_400, time: new Date('2022-07-31T00:00:00.000Z') }
}
];

const SomeByronSlot = Cardano.Slot(1_209_592);

describe('slotCalc utils', () => {
describe('epochStartCalc', () => {
describe('preprod', () => {
it('correctly computes 1st slot of the 0th epoch', () => {
const { firstSlot, lastSlot } = epochSlotsCalc(Cardano.EpochNo(0), preprodEraSummaries);
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);
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);
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);
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);
expect(firstSlot).toBe(518_400);
expect(lastSlot).toBe(950_399);
});

it('correctly computes 1st slot of some epoch of the last era summary and aligns with epochSlotCalc', () => {
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);
expect(firstSlot).toBe(expectedFirstSlot);
expect(lastSlot).toBe(expectedLastSlot);
const epochSlotCalc = createSlotEpochCalc(preprodEraSummaries);
expect(epochSlotCalc(expectedFirstSlot)).toEqual(epoch);
expect(epochSlotCalc(Cardano.Slot(expectedFirstSlot - 1))).toEqual(epoch - 1);
expect(epochSlotCalc(expectedLastSlot)).toEqual(epoch);
expect(epochSlotCalc(Cardano.Slot(expectedLastSlot + 1))).toEqual(epoch + 1);
});
});
});

describe('slotTimeCalc', () => {
describe('testnet', () => {
const slotTimeCalc: SlotTimeCalc = createSlotTimeCalc(testnetEraSummaries);
Expand All @@ -46,7 +125,7 @@ describe('slotCalc utils', () => {
expect(slotTimeCalc(Cardano.Slot(0))).toEqual(new Date(1_563_999_616_000)));

it('correctly computes date of some Byron block', () =>
expect(slotTimeCalc(Cardano.Slot(1_209_592))).toEqual(new Date(1_588_191_456_000)));
expect(slotTimeCalc(SomeByronSlot)).toEqual(new Date(1_588_191_456_000)));

it('correctly computes date of the last Byron block', () =>
expect(slotTimeCalc(Cardano.Slot(1_598_399))).toEqual(new Date(1_595_967_596_000)));
Expand Down

0 comments on commit 266b951

Please sign in to comment.