diff --git a/web3.js/flow-typed/superstruct.js b/web3.js/flow-typed/superstruct.js index 0384daf593..43c8e5b173 100644 --- a/web3.js/flow-typed/superstruct.js +++ b/web3.js/flow-typed/superstruct.js @@ -6,6 +6,7 @@ declare module 'superstruct' { literal(schema: any): any; tuple(schema: any): any; pick(schema: any): any; + record(schema: any): any; }; declare module.exports: { diff --git a/web3.js/module.d.ts b/web3.js/module.d.ts index 8cc1adcf9d..d1dd1ff4e6 100644 --- a/web3.js/module.d.ts +++ b/web3.js/module.d.ts @@ -193,6 +193,10 @@ declare module '@solana/web3.js' { firstNormalSlot: number; }; + export type LeaderSchedule = { + [address: string]: number[]; + }; + export type Supply = { total: number; circulating: number; @@ -266,6 +270,7 @@ declare module '@solana/web3.js' { getTotalSupply(commitment?: Commitment): Promise; getVersion(): Promise; getInflationGovernor(commitment?: Commitment): Promise; + getLeaderSchedule(): Promise; getEpochSchedule(): Promise; getEpochInfo(commitment?: Commitment): Promise; getRecentBlockhashAndContext( diff --git a/web3.js/module.flow.js b/web3.js/module.flow.js index d2faa9be82..a2ba4e0f4c 100644 --- a/web3.js/module.flow.js +++ b/web3.js/module.flow.js @@ -210,6 +210,10 @@ declare module '@solana/web3.js' { absoluteSlot: number, }; + declare export type LeaderSchedule = { + [address: string]: number[], + }; + declare export type Supply = { total: number, circulating: number, @@ -283,6 +287,7 @@ declare module '@solana/web3.js' { getTotalSupply(commitment: ?Commitment): Promise; getVersion(): Promise; getInflationGovernor(commitment: ?Commitment): Promise; + getLeaderSchedule(): Promise; getEpochSchedule(): Promise; getEpochInfo(commitment: ?Commitment): Promise; getRecentBlockhashAndContext( diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index 2a505f9926..ee831a4be2 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -288,6 +288,21 @@ const GetEpochScheduleResult = struct({ firstNormalSlot: 'number', }); +/** + * Leader schedule + * (see https://docs.solana.com/terminology#leader-schedule) + * + * @typedef {Object} LeaderSchedule + */ +type LeaderSchedule = { + [address: string]: number[], +}; + +const GetLeaderScheduleResult = struct.record([ + 'string', + struct.array(['number']), +]); + /** * Transaction error or null */ @@ -424,6 +439,13 @@ const GetEpochScheduleRpcResult = struct({ result: GetEpochScheduleResult, }); +/** + * Expected JSON RPC response for the "getLeaderSchedule" message + */ +const GetLeaderScheduleRpcResult = jsonRpcResult( + GetLeaderScheduleResult, +); + /** * Expected JSON RPC response for the "getBalance" message */ @@ -1476,6 +1498,20 @@ export class Connection { return GetEpochScheduleResult(res.result); } + /** + * Fetch the leader schedule for the current epoch + * @return {Promise>} + */ + async getLeaderSchedule(): Promise { + const unsafeRes = await this._rpcRequest('getLeaderSchedule', []); + const res = GetLeaderScheduleRpcResult(unsafeRes); + if (res.error) { + throw new Error('failed to get leader schedule: ' + res.error.message); + } + assert(typeof res.result !== 'undefined'); + return res.result; + } + /** * Fetch the minimum balance needed to exempt an account of `dataLength` * size from rent diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index 610bdbf63e..2e8a54e744 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -443,6 +443,33 @@ test('get epoch schedule', async () => { } }); +test('get leader schedule', async () => { + const connection = new Connection(url); + + mockRpc.push([ + url, + { + method: 'getLeaderSchedule', + params: [], + }, + { + error: null, + result: { + '123vij84ecQEKUvQ7gYMKxKwKF6PbYSzCzzURYA4xULY': [0, 1, 2, 3], + '8PTjAikKoAybKXcEPnDSoy8wSNNikUBJ1iKawJKQwXnB': [4, 5, 6, 7], + }, + }, + ]); + + const leaderSchedule = await connection.getLeaderSchedule(); + expect(Object.keys(leaderSchedule).length).toBeGreaterThanOrEqual(1); + for (const key in leaderSchedule) { + const slots = leaderSchedule[key]; + expect(Array.isArray(slots)).toBe(true); + expect(slots.length).toBeGreaterThanOrEqual(4); + } +}); + test('get slot', async () => { const connection = new Connection(url);