feat: introduce getRecentPerformanceSamples rpc (#12442)
* feat: introduce getRecentPerformanceSamples rpc * test: indroduce tests and clean up style * test: skip live tests * feat: run tests live
This commit is contained in:
		
							
								
								
									
										8
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -155,6 +155,13 @@ declare module '@solana/web3.js' { | ||||
|     }>; | ||||
|   }; | ||||
|  | ||||
|   export type PerfSample = { | ||||
|     slot: number; | ||||
|     numTransactions: number; | ||||
|     numSlots: number; | ||||
|     samplePeriodSecs: number; | ||||
|   }; | ||||
|  | ||||
|   export type ConfirmedTransaction = { | ||||
|     slot: number; | ||||
|     transaction: Transaction; | ||||
| @@ -421,6 +428,7 @@ declare module '@solana/web3.js' { | ||||
|     getRecentBlockhashAndContext( | ||||
|       commitment?: Commitment, | ||||
|     ): Promise<RpcResponseAndContext<BlockhashAndFeeCalculator>>; | ||||
|     getRecentPerformanceSamples(limit?: number): Promise<Array<PerfSample>>; | ||||
|     getFeeCalculatorForBlockhash( | ||||
|       blockhash: Blockhash, | ||||
|       commitment?: Commitment, | ||||
|   | ||||
| @@ -169,6 +169,13 @@ declare module '@solana/web3.js' { | ||||
|     }>, | ||||
|   }; | ||||
|  | ||||
|   declare export type PerfSample = { | ||||
|     slot: number, | ||||
|     numTransactions: number, | ||||
|     numSlots: number, | ||||
|     samplePeriodSecs: number, | ||||
|   }; | ||||
|  | ||||
|   declare export type ConfirmedTransaction = { | ||||
|     slot: number, | ||||
|     transaction: Transaction, | ||||
| @@ -426,6 +433,7 @@ declare module '@solana/web3.js' { | ||||
|     getRecentBlockhashAndContext( | ||||
|       commitment: ?Commitment, | ||||
|     ): Promise<RpcResponseAndContext<BlockhashAndFeeCalculator>>; | ||||
|     getRecentPerformanceSamples(limit: ?number): Promise<Array<PerfSample>>; | ||||
|     getFeeCalculatorForBlockhash( | ||||
|       blockhash: Blockhash, | ||||
|       commitment: ?Commitment, | ||||
|   | ||||
| @@ -505,8 +505,25 @@ type ConfirmedBlock = { | ||||
|   }>, | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * A performance sample | ||||
|  * | ||||
|  * @typedef {Object} PerfSample | ||||
|  * @property {number} slot Slot number of sample | ||||
|  * @property {number} numTransactions Number of transactions in a sample window | ||||
|  * @property {number} numSlots Number of slots in a sample window | ||||
|  * @property {number} samplePeriodSecs Sample window in seconds | ||||
|  */ | ||||
| type PerfSample = { | ||||
|   slot: number, | ||||
|   numTransactions: number, | ||||
|   numSlots: number, | ||||
|   samplePeriodSecs: number, | ||||
| }; | ||||
|  | ||||
| function createRpcRequest(url: string, useHttps: boolean): RpcRequest { | ||||
|   const agentManager = new AgentManager(useHttps); | ||||
|  | ||||
|   const server = jayson(async (request, callback) => { | ||||
|     const agent = agentManager.requestStart(); | ||||
|     const options = { | ||||
| @@ -1182,6 +1199,20 @@ const GetRecentBlockhashAndContextRpcResult = jsonRpcResultAndContext( | ||||
|   }), | ||||
| ); | ||||
|  | ||||
| /* | ||||
|  * Expected JSON RPC response for "getRecentPerformanceSamples" message | ||||
|  */ | ||||
| const GetRecentPerformanceSamplesRpcResult = jsonRpcResult( | ||||
|   struct.array([ | ||||
|     struct.pick({ | ||||
|       slot: 'number', | ||||
|       numTransactions: 'number', | ||||
|       numSlots: 'number', | ||||
|       samplePeriodSecs: 'number', | ||||
|     }), | ||||
|   ]), | ||||
| ); | ||||
|  | ||||
| /** | ||||
|  * Expected JSON RPC response for the "getFeeCalculatorForBlockhash" message | ||||
|  */ | ||||
| @@ -2325,6 +2356,30 @@ export class Connection { | ||||
|     return res.result; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Fetch recent performance samples | ||||
|    * @return {Promise<Array<PerfSample>>} | ||||
|    */ | ||||
|   async getRecentPerformanceSamples( | ||||
|     limit: ?number, | ||||
|   ): Promise<Array<PerfSample>> { | ||||
|     const args = this._buildArgs(limit ? [limit] : []); | ||||
|     const unsafeRes = await this._rpcRequest( | ||||
|       'getRecentPerformanceSamples', | ||||
|       args, | ||||
|     ); | ||||
|  | ||||
|     const res = GetRecentPerformanceSamplesRpcResult(unsafeRes); | ||||
|     if (res.error) { | ||||
|       throw new Error( | ||||
|         'failed to get recent performance samples: ' + res.error.message, | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     assert(typeof res.result !== 'undefined'); | ||||
|     return res.result; | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Fetch the fee calculator for a recent blockhash from the cluster, return with context | ||||
|    */ | ||||
|   | ||||
| @@ -1279,6 +1279,66 @@ test('get supply', async () => { | ||||
|   expect(supply.nonCirculatingAccounts.length).toBeGreaterThan(0); | ||||
| }); | ||||
|  | ||||
| test('get performance samples', async () => { | ||||
|   const connection = new Connection(url); | ||||
|  | ||||
|   if (mockRpcEnabled) { | ||||
|     mockRpc.push([ | ||||
|       url, | ||||
|       { | ||||
|         method: 'getRecentPerformanceSamples', | ||||
|         params: [], | ||||
|       }, | ||||
|       { | ||||
|         error: null, | ||||
|         result: [ | ||||
|           { | ||||
|             slot: 1234, | ||||
|             numTransactions: 1000, | ||||
|             numSlots: 60, | ||||
|             samplePeriodSecs: 60, | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     ]); | ||||
|   } | ||||
|  | ||||
|   const perfSamples = await connection.getRecentPerformanceSamples(); | ||||
|   expect(Array.isArray(perfSamples)).toBe(true); | ||||
|  | ||||
|   if (perfSamples.length > 0) { | ||||
|     expect(perfSamples[0].slot).toBeGreaterThan(0); | ||||
|     expect(perfSamples[0].numTransactions).toBeGreaterThan(0); | ||||
|     expect(perfSamples[0].numSlots).toBeGreaterThan(0); | ||||
|     expect(perfSamples[0].samplePeriodSecs).toBeGreaterThan(0); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| test('get performance samples limit too high', async () => { | ||||
|   const connection = new Connection(url); | ||||
|  | ||||
|   if (mockRpcEnabled) { | ||||
|     mockRpc.push([ | ||||
|       url, | ||||
|       { | ||||
|         method: 'getRecentPerformanceSamples', | ||||
|         params: [100000], | ||||
|       }, | ||||
|       { | ||||
|         error: { | ||||
|           code: -32602, | ||||
|           message: 'Invalid limit; max 720', | ||||
|         }, | ||||
|         result: null, | ||||
|       }, | ||||
|     ]); | ||||
|   } | ||||
|  | ||||
|   await expect( | ||||
|     connection.getRecentPerformanceSamples(100000), | ||||
|   ).rejects.toThrow(); | ||||
| }); | ||||
|  | ||||
| const TOKEN_PROGRAM_ID = new PublicKey( | ||||
|   'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', | ||||
| ); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user