import { assertAccountExists, decodeAccount, type FetchAccountConfig } from '@solana/accounts'; import { combineCodec, type FixedSizeCodec, type FixedSizeDecoder, type FixedSizeEncoder } from '@solana/codecs-core'; import { getBooleanDecoder, getBooleanEncoder, getStructDecoder, getStructEncoder, } from '@solana/codecs-data-structures'; import { getU64Decoder, getU64Encoder } from '@solana/codecs-numbers'; import type { GetAccountInfoApi } from '@solana/rpc-api'; import type { Rpc } from '@solana/rpc-spec'; import type { Epoch, Slot } from '@solana/rpc-types'; import { fetchEncodedSysvarAccount, SYSVAR_EPOCH_SCHEDULE_ADDRESS } from './sysvar'; type SysvarEpochScheduleSize = 33; /** * Includes the number of slots per epoch, timing of leader schedule selection, and information * about epoch warm-up time. */ export type SysvarEpochSchedule = Readonly<{ /** * First normal-length epoch after the warmup period, * log2(slotsPerEpoch) - log2(MINIMUM_SLOTS_PER_EPOCH) */ firstNormalEpoch: Epoch; /** * The first slot after the warmup period, MINIMUM_SLOTS_PER_EPOCH * (2^(firstNormalEpoch) - 1) */ firstNormalSlot: Slot; /** * A number of slots before beginning of an epoch to calculate a leader schedule for that * epoch. */ leaderScheduleSlotOffset: bigint; /** The maximum number of slots in each epoch */ slotsPerEpoch: bigint; /** Whether epochs start short and grow */ warmup: boolean; }>; /** * Returns an encoder that you can use to encode a {@link SysvarEpochSchedule} to a byte array * representing the `EpochSchedule` sysvar's account data. */ export function getSysvarEpochScheduleEncoder(): FixedSizeEncoder { return getStructEncoder([ ['slotsPerEpoch', getU64Encoder()], ['leaderScheduleSlotOffset', getU64Encoder()], ['warmup', getBooleanEncoder()], ['firstNormalEpoch', getU64Encoder()], ['firstNormalSlot', getU64Encoder()], ]) as FixedSizeEncoder; } /** * Returns a decoder that you can use to decode a byte array representing the `EpochSchedule` * sysvar's account data to a {@link SysvarEpochSchedule}. */ export function getSysvarEpochScheduleDecoder(): FixedSizeDecoder { return getStructDecoder([ ['slotsPerEpoch', getU64Decoder()], ['leaderScheduleSlotOffset', getU64Decoder()], ['warmup', getBooleanDecoder()], ['firstNormalEpoch', getU64Decoder()], ['firstNormalSlot', getU64Decoder()], ]) as FixedSizeDecoder; } /** * Returns a codec that you can use to encode from or decode to {@link SysvarEpochSchedule} * * @see {@link getSysvarEpochScheduleDecoder} * @see {@link getSysvarEpochScheduleEncoder} */ export function getSysvarEpochScheduleCodec(): FixedSizeCodec< SysvarEpochSchedule, SysvarEpochSchedule, SysvarEpochScheduleSize > { return combineCodec(getSysvarEpochScheduleEncoder(), getSysvarEpochScheduleDecoder()); } /** * Fetches the `EpochSchedule` sysvar account using any RPC that supports the * {@link GetAccountInfoApi}. */ export async function fetchSysvarEpochSchedule( rpc: Rpc, config?: FetchAccountConfig, ): Promise { const account = await fetchEncodedSysvarAccount(rpc, SYSVAR_EPOCH_SCHEDULE_ADDRESS, config); assertAccountExists(account); const decoded = decodeAccount(account, getSysvarEpochScheduleDecoder()); return decoded.data; }