Skip to content

Commit

Permalink
refactor(experimental): sysvars package: last restart slot
Browse files Browse the repository at this point in the history
This commit introduces the `LastRestartSlot` sysvar to the `@solana/sysvars` package.
  • Loading branch information
buffalojoec committed Mar 14, 2024
1 parent c835722 commit d607ab4
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 1 deletion.
25 changes: 25 additions & 0 deletions packages/sysvars/src/__tests__/last-restart-slot-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { GetAccountInfoApi } from '@solana/rpc-api';
import type { Rpc } from '@solana/rpc-spec';

import { fetchSysvarLastRestartSlot, getSysvarLastRestartSlotCodec } from '../last-restart-slot';
import { createLocalhostSolanaRpc } from './__setup__';

describe('last restart slot', () => {
let rpc: Rpc<GetAccountInfoApi>;
beforeEach(() => {
rpc = createLocalhostSolanaRpc();
});
it('decode', () => {
const lastRestartSlotState = new Uint8Array([119, 233, 246, 16, 0, 0, 0, 0]);
expect(getSysvarLastRestartSlotCodec().decode(lastRestartSlotState)).toMatchObject({
lastRestartSlot: 284_617_079n,
});
});
it('fetch', async () => {
expect.assertions(1);
const lastRestartSlot = await fetchSysvarLastRestartSlot(rpc);
expect(lastRestartSlot).toMatchObject({
lastRestartSlot: expect.any(BigInt),
});
});
});
15 changes: 15 additions & 0 deletions packages/sysvars/src/__tests__/sysvar-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
SYSVAR_CLOCK_ADDRESS,
SYSVAR_EPOCH_SCHEDULE_ADDRESS,
SYSVAR_FEES_ADDRESS,
SYSVAR_LAST_RESTART_SLOT_ADDRESS,
} from '../sysvar';
import { createLocalhostSolanaRpc } from './__setup__';

Expand Down Expand Up @@ -88,4 +89,18 @@ describe('sysvar account', () => {
});
});
// `Instructions` does not exist on-chain.
describe('last restart slot', () => {
it('fetch encoded', async () => {
expect.assertions(3);
await assertValidEncodedSysvarAccount(SYSVAR_LAST_RESTART_SLOT_ADDRESS);
});
it('fetch JSON-parsed', async () => {
expect.assertions(3);
await assertValidJsonParsedSysvarAccount(SYSVAR_LAST_RESTART_SLOT_ADDRESS, {
data: {
lastRestartSlot: expect.any(BigInt),
},
});
});
});
});
9 changes: 9 additions & 0 deletions packages/sysvars/src/__typetests__/sysvar-typetest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { fetchSysvarClock, type SysvarClock } from '../clock';
import { fetchSysvarEpochRewards, type SysvarEpochRewards } from '../epoch-rewards';
import { fetchSysvarEpochSchedule, type SysvarEpochSchedule } from '../epoch-schedule';
import { fetchSysvarFees, type SysvarFees } from '../fees';
import { fetchSysvarLastRestartSlot, type SysvarLastRestartSlot } from '../last-restart-slot';
import { fetchEncodedSysvarAccount, fetchJsonParsedSysvarAccount, SYSVAR_CLOCK_ADDRESS } from '../sysvar';

const rpc = null as unknown as Parameters<typeof fetchEncodedSysvarAccount>[0];
Expand Down Expand Up @@ -79,3 +80,11 @@ const rpc = null as unknown as Parameters<typeof fetchEncodedSysvarAccount>[0];
// @ts-expect-error Returns a `SysvarFees`.
fetchSysvarFees(rpc) satisfies Promise<{ foo: string }>;
}

// `fetchSysvarLastRestartSlot`
{
// Returns a `SysvarLastRestartSlot`.
fetchSysvarLastRestartSlot(rpc) satisfies Promise<SysvarLastRestartSlot>;
// @ts-expect-error Returns a `SysvarLastRestartSlot`.
fetchSysvarLastRestartSlot(rpc) satisfies Promise<{ foo: string }>;
}
1 change: 1 addition & 0 deletions packages/sysvars/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export * from './clock';
export * from './epoch-rewards';
export * from './epoch-schedule';
export * from './fees';
export * from './last-restart-slot';
export * from './sysvar';
72 changes: 72 additions & 0 deletions packages/sysvars/src/last-restart-slot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { assertAccountExists, decodeAccount, type FetchAccountConfig } from '@solana/accounts';
import {
combineCodec,
type FixedSizeCodec,
type FixedSizeDecoder,
type FixedSizeEncoder,
getStructDecoder,
getStructEncoder,
getU64Decoder,
getU64Encoder,
} from '@solana/codecs';
import type { GetAccountInfoApi } from '@solana/rpc-api';
import type { Rpc } from '@solana/rpc-spec';
import type { Slot } from '@solana/rpc-types';

import { fetchEncodedSysvarAccount, SYSVAR_LAST_RESTART_SLOT_ADDRESS } from './sysvar';

type SysvarLastRestartSlotSize = 8;

/**
* The `LastRestartSlot` sysvar.
*
* Information about the last restart slot (hard fork).
*
* The `LastRestartSlot` sysvar provides access to the last restart slot kept in the
* bank fork for the slot on the fork that executes the current transaction.
* In case there was no fork it returns `0`.
*/
export type SysvarLastRestartSlot = Readonly<{
lastRestartSlot: Slot;
}>;

export function getSysvarLastRestartSlotEncoder(): FixedSizeEncoder<SysvarLastRestartSlot, SysvarLastRestartSlotSize> {
return getStructEncoder([['lastRestartSlot', getU64Encoder()]]) as FixedSizeEncoder<
SysvarLastRestartSlot,
SysvarLastRestartSlotSize
>;
}

export function getSysvarLastRestartSlotDecoder(): FixedSizeDecoder<SysvarLastRestartSlot, SysvarLastRestartSlotSize> {
return getStructDecoder([['lastRestartSlot', getU64Decoder()]]) as FixedSizeDecoder<
SysvarLastRestartSlot,
SysvarLastRestartSlotSize
>;
}

export function getSysvarLastRestartSlotCodec(): FixedSizeCodec<
SysvarLastRestartSlot,
SysvarLastRestartSlot,
SysvarLastRestartSlotSize
> {
return combineCodec(getSysvarLastRestartSlotEncoder(), getSysvarLastRestartSlotDecoder());
}

/**
* Fetch the `LastRestartSlot` sysvar.
*
* Information about the last restart slot (hard fork).
*
* The `LastRestartSlot` sysvar provides access to the last restart slot kept in the
* bank fork for the slot on the fork that executes the current transaction.
* In case there was no fork it returns `0`.
*/
export async function fetchSysvarLastRestartSlot(
rpc: Rpc<GetAccountInfoApi>,
config?: FetchAccountConfig,
): Promise<SysvarLastRestartSlot> {
const account = await fetchEncodedSysvarAccount(rpc, SYSVAR_LAST_RESTART_SLOT_ADDRESS, config);
assertAccountExists(account);
const decoded = decodeAccount(account, getSysvarLastRestartSlotDecoder());
return decoded.data;
}
5 changes: 4 additions & 1 deletion packages/sysvars/src/sysvar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ export const SYSVAR_FEES_ADDRESS =
'SysvarFees111111111111111111111111111111111' as Address<'SysvarFees111111111111111111111111111111111'>;
export const SYSVAR_INSTRUCTIONS_ADDRESS =
'Sysvar1nstructions1111111111111111111111111' as Address<'Sysvar1nstructions1111111111111111111111111'>;
export const SYSVAR_LAST_RESTART_SLOT_ADDRESS =
'SysvarLastRestartS1ot1111111111111111111111' as Address<'SysvarLastRestartS1ot1111111111111111111111'>;

type SysvarAddress =
| typeof SYSVAR_CLOCK_ADDRESS
| typeof SYSVAR_EPOCH_REWARDS_ADDRESS
| typeof SYSVAR_EPOCH_SCHEDULE_ADDRESS
| typeof SYSVAR_FEES_ADDRESS
| typeof SYSVAR_INSTRUCTIONS_ADDRESS;
| typeof SYSVAR_INSTRUCTIONS_ADDRESS
| typeof SYSVAR_LAST_RESTART_SLOT_ADDRESS;

/**
* Fetch an encoded sysvar account.
Expand Down

0 comments on commit d607ab4

Please sign in to comment.