diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index b80fbd4055..0616d5ba6d 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -21,18 +21,34 @@ type RpcRequest = (methodName: string, args: Array) => any; * Information describing a cluster node * * @typedef {Object} ContactInfo - * @property {string} id Unique identifier of the node + * @property {string} pubkey Identity public key of the node * @property {string} gossip Gossip network address for the node * @property {string} tpu TPU network address for the node (null if not available) * @property {string|null} rpc JSON RPC network address for the node (null if not available) */ type ContactInfo = { - id: string, + pubkey: string, gossip: string, tpu: string | null, rpc: string | null, }; +/** + * Information describing a vote account + * + * @typedef {Object} VoteAccountInfo + * @property {string} votePubkey Public key of the vote account + * @property {string} nodePubkey Identity public key of the node voting with this account + * @property {string} stake The stake, in lamports, delegated to this vote account + * @property {string} commission A 32-bit integer used as a fraction (commission/0xFFFFFFFF) for rewards payout + */ +type VoteAccountInfo = { + votePubkey: string, + nodePubkey: string, + stake: number, + commission: number, +}; + function createRpcRequest(url): RpcRequest { const server = jayson(async (request, callback) => { const options = { @@ -147,7 +163,7 @@ const GetSlotLeader = jsonRpcResult('string'); const GetClusterNodes = jsonRpcResult( struct.list([ struct({ - id: 'string', + pubkey: 'string', gossip: 'string', tpu: struct.union(['null', 'string']), rpc: struct.union(['null', 'string']), @@ -155,6 +171,20 @@ const GetClusterNodes = jsonRpcResult( ]), ); +/** + * Expected JSON RPC response for the "getEpochVoteAccounts" message + */ +const GetEpochVoteAccounts = jsonRpcResult( + struct.list([ + struct({ + votePubkey: 'string', + nodePubkey: 'string', + stake: 'number', + commission: 'number', + }), + ]), +); + /** * Expected JSON RPC response for the "getSignatureStatus" message */ @@ -373,11 +403,11 @@ export class Connection { } /** - * Fetch the current slot leader of the cluster + * Return the list of nodes that are currently participating in the cluster */ - async getSlotLeader(): Promise { - const unsafeRes = await this._rpcRequest('getSlotLeader', []); - const res = GetSlotLeader(unsafeRes); + async getClusterNodes(): Promise> { + const unsafeRes = await this._rpcRequest('getClusterNodes', []); + const res = GetClusterNodes(unsafeRes); if (res.error) { throw new Error(res.error.message); } @@ -388,9 +418,23 @@ export class Connection { /** * Return the list of nodes that are currently participating in the cluster */ - async getClusterNodes(): Promise> { - const unsafeRes = await this._rpcRequest('getClusterNodes', []); - const res = GetClusterNodes(unsafeRes); + async getEpochVoteAccounts(): Promise> { + const unsafeRes = await this._rpcRequest('getEpochVoteAccounts', []); + const res = GetEpochVoteAccounts(unsafeRes); + //const res = unsafeRes; + if (res.error) { + throw new Error(res.error.message); + } + assert(typeof res.result !== 'undefined'); + return res.result; + } + + /** + * Fetch the current slot leader of the cluster + */ + async getSlotLeader(): Promise { + const unsafeRes = await this._rpcRequest('getSlotLeader', []); + const res = GetSlotLeader(unsafeRes); if (res.error) { throw new Error(res.error.message); } diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index 6f01a293ee..4f56b22da9 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -115,7 +115,7 @@ test('get cluster nodes', async () => { error: null, result: [ { - id: '11111111111111111111111111111111', + pubkey: '11111111111111111111111111111111', gossip: '127.0.0.0:1234', tpu: '127.0.0.0:1235', rpc: null, @@ -127,7 +127,7 @@ test('get cluster nodes', async () => { const clusterNodes = await connection.getClusterNodes(); if (mockRpcEnabled) { expect(clusterNodes).toHaveLength(1); - expect(clusterNodes[0].id).toBe('11111111111111111111111111111111'); + expect(clusterNodes[0].pubkey).toBe('11111111111111111111111111111111'); expect(typeof clusterNodes[0].gossip).toBe('string'); expect(typeof clusterNodes[0].tpu).toBe('string'); expect(clusterNodes[0].rpc).toBeNull(); @@ -137,6 +137,17 @@ test('get cluster nodes', async () => { } }); +test('getEpochVoteAccounts', async () => { + if (mockRpcEnabled) { + console.log('non-live test skipped'); + return; + } + + const connection = new Connection(url); + const voteAccounts = await connection.getEpochVoteAccounts(); + expect(voteAccounts.length).toBeGreaterThan(0); +}); + test('confirm transaction - error', () => { const connection = new Connection(url);