feat: add getConfirmedTransaction and getConfirmedSignaturesForAddress
This commit is contained in:
		
				
					committed by
					
						 Michael Vines
						Michael Vines
					
				
			
			
				
	
			
			
			
						parent
						
							7f182d22cd
						
					
				
				
					commit
					ae53742e1a
				
			
							
								
								
									
										19
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								web3.js/module.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -98,6 +98,17 @@ declare module '@solana/web3.js' { | |||||||
|     }>; |     }>; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   export type ConfirmedTransaction = { | ||||||
|  |     slot: number; | ||||||
|  |     transaction: Transaction; | ||||||
|  |     meta: { | ||||||
|  |       fee: number; | ||||||
|  |       preBalances: Array<number>; | ||||||
|  |       postBalances: Array<number>; | ||||||
|  |       err: TransactionError | null; | ||||||
|  |     } | null; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   export type KeyedAccountInfo = { |   export type KeyedAccountInfo = { | ||||||
|     accountId: PublicKey; |     accountId: PublicKey; | ||||||
|     accountInfo: AccountInfo; |     accountInfo: AccountInfo; | ||||||
| @@ -184,6 +195,14 @@ declare module '@solana/web3.js' { | |||||||
|     getBalance(publicKey: PublicKey, commitment?: Commitment): Promise<number>; |     getBalance(publicKey: PublicKey, commitment?: Commitment): Promise<number>; | ||||||
|     getClusterNodes(): Promise<Array<ContactInfo>>; |     getClusterNodes(): Promise<Array<ContactInfo>>; | ||||||
|     getConfirmedBlock(slot: number): Promise<ConfirmedBlock>; |     getConfirmedBlock(slot: number): Promise<ConfirmedBlock>; | ||||||
|  |     getConfirmedTransaction( | ||||||
|  |       signature: TransactionSignature, | ||||||
|  |     ): Promise<ConfirmedTransaction | null>; | ||||||
|  |     getConfirmedSignaturesForAddress( | ||||||
|  |       address: PublicKey, | ||||||
|  |       startSlot: number, | ||||||
|  |       endSlot: number, | ||||||
|  |     ): Promise<Array<TransactionSignature>>; | ||||||
|     getVoteAccounts(commitment?: Commitment): Promise<VoteAccountStatus>; |     getVoteAccounts(commitment?: Commitment): Promise<VoteAccountStatus>; | ||||||
|     confirmTransactionAndContext( |     confirmTransactionAndContext( | ||||||
|       signature: TransactionSignature, |       signature: TransactionSignature, | ||||||
|   | |||||||
| @@ -111,6 +111,17 @@ declare module '@solana/web3.js' { | |||||||
|     }>, |     }>, | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  |   declare export type ConfirmedTransaction = { | ||||||
|  |     slot: number, | ||||||
|  |     transaction: Transaction, | ||||||
|  |     meta: { | ||||||
|  |       fee: number, | ||||||
|  |       preBalances: Array<number>, | ||||||
|  |       postBalances: Array<number>, | ||||||
|  |       err: TransactionError | null, | ||||||
|  |     } | null, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   declare export type KeyedAccountInfo = { |   declare export type KeyedAccountInfo = { | ||||||
|     accountId: PublicKey, |     accountId: PublicKey, | ||||||
|     accountInfo: AccountInfo, |     accountInfo: AccountInfo, | ||||||
| @@ -197,6 +208,14 @@ declare module '@solana/web3.js' { | |||||||
|     getBalance(publicKey: PublicKey, commitment: ?Commitment): Promise<number>; |     getBalance(publicKey: PublicKey, commitment: ?Commitment): Promise<number>; | ||||||
|     getClusterNodes(): Promise<Array<ContactInfo>>; |     getClusterNodes(): Promise<Array<ContactInfo>>; | ||||||
|     getConfirmedBlock(slot: number): Promise<ConfirmedBlock>; |     getConfirmedBlock(slot: number): Promise<ConfirmedBlock>; | ||||||
|  |     getConfirmedTransaction( | ||||||
|  |       signature: TransactionSignature, | ||||||
|  |     ): Promise<ConfirmedTransaction | null>; | ||||||
|  |     getConfirmedSignaturesForAddress( | ||||||
|  |       address: PublicKey, | ||||||
|  |       startSlot: number, | ||||||
|  |       endSlot: number, | ||||||
|  |     ): Promise<Array<TransactionSignature>>; | ||||||
|     getVoteAccounts(commitment: ?Commitment): Promise<VoteAccountStatus>; |     getVoteAccounts(commitment: ?Commitment): Promise<VoteAccountStatus>; | ||||||
|     confirmTransactionAndContext( |     confirmTransactionAndContext( | ||||||
|       signature: TransactionSignature, |       signature: TransactionSignature, | ||||||
|   | |||||||
| @@ -233,6 +233,25 @@ const Version = struct({ | |||||||
|   'solana-core': 'string', |   'solana-core': 'string', | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A confirmed transaction on the ledger | ||||||
|  |  * | ||||||
|  |  * @typedef {Object} ConfirmedTransaction | ||||||
|  |  * @property {number} slot The slot during which the transaction was processed | ||||||
|  |  * @property {Transaction} transaction The details of the transaction | ||||||
|  |  * @property {object} meta Slot index of this block's parent | ||||||
|  |  */ | ||||||
|  | type ConfirmedTransaction = { | ||||||
|  |   slot: number, | ||||||
|  |   transaction: Transaction, | ||||||
|  |   meta: { | ||||||
|  |     fee: number, | ||||||
|  |     err: TransactionError | null, | ||||||
|  |     preBalances: Array<number>, | ||||||
|  |     postBalances: Array<number>, | ||||||
|  |   } | null, | ||||||
|  | }; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * A ConfirmedBlock on the ledger |  * A ConfirmedBlock on the ledger | ||||||
|  * |  * | ||||||
| @@ -357,6 +376,13 @@ const GetAccountInfoAndContextRpcResult = jsonRpcResultAndContext( | |||||||
|   struct.union(['null', AccountInfoResult]), |   struct.union(['null', AccountInfoResult]), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | const GetConfirmedSignaturesForAddressRpcResult = jsonRpcResult( | ||||||
|  |   struct.array(['string']), | ||||||
|  | ); | ||||||
|  |  | ||||||
| /*** | /*** | ||||||
|  * Expected JSON RPC response for the "accountNotification" message |  * Expected JSON RPC response for the "accountNotification" message | ||||||
|  */ |  */ | ||||||
| @@ -519,6 +545,45 @@ const GetTotalSupplyRpcResult = jsonRpcResult('number'); | |||||||
|  */ |  */ | ||||||
| const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult('number'); | const GetMinimumBalanceForRentExemptionRpcResult = jsonRpcResult('number'); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | const ConfirmedTransactionResult = struct({ | ||||||
|  |   signatures: struct.array(['string']), | ||||||
|  |   message: struct({ | ||||||
|  |     accountKeys: struct.array(['string']), | ||||||
|  |     header: struct({ | ||||||
|  |       numRequiredSignatures: 'number', | ||||||
|  |       numReadonlySignedAccounts: 'number', | ||||||
|  |       numReadonlyUnsignedAccounts: 'number', | ||||||
|  |     }), | ||||||
|  |     instructions: struct.array([ | ||||||
|  |       struct.union([ | ||||||
|  |         struct.array(['number']), | ||||||
|  |         struct({ | ||||||
|  |           accounts: struct.array(['number']), | ||||||
|  |           data: 'string', | ||||||
|  |           programIdIndex: 'number', | ||||||
|  |         }), | ||||||
|  |       ]), | ||||||
|  |     ]), | ||||||
|  |     recentBlockhash: 'string', | ||||||
|  |   }), | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @private | ||||||
|  |  */ | ||||||
|  | const ConfirmedTransactionMetaResult = struct.union([ | ||||||
|  |   'null', | ||||||
|  |   struct.pick({ | ||||||
|  |     err: TransactionErrorResult, | ||||||
|  |     fee: 'number', | ||||||
|  |     preBalances: struct.array(['number']), | ||||||
|  |     postBalances: struct.array(['number']), | ||||||
|  |   }), | ||||||
|  | ]); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Expected JSON RPC response for the "getConfirmedBlock" message |  * Expected JSON RPC response for the "getConfirmedBlock" message | ||||||
|  */ |  */ | ||||||
| @@ -531,37 +596,8 @@ export const GetConfirmedBlockRpcResult = jsonRpcResult( | |||||||
|       parentSlot: 'number', |       parentSlot: 'number', | ||||||
|       transactions: struct.array([ |       transactions: struct.array([ | ||||||
|         struct({ |         struct({ | ||||||
|           transaction: struct({ |           transaction: ConfirmedTransactionResult, | ||||||
|             signatures: struct.array(['string']), |           meta: ConfirmedTransactionMetaResult, | ||||||
|             message: struct({ |  | ||||||
|               accountKeys: struct.array(['string']), |  | ||||||
|               header: struct({ |  | ||||||
|                 numRequiredSignatures: 'number', |  | ||||||
|                 numReadonlySignedAccounts: 'number', |  | ||||||
|                 numReadonlyUnsignedAccounts: 'number', |  | ||||||
|               }), |  | ||||||
|               instructions: struct.array([ |  | ||||||
|                 struct.union([ |  | ||||||
|                   struct.array(['number']), |  | ||||||
|                   struct({ |  | ||||||
|                     accounts: struct.array(['number']), |  | ||||||
|                     data: 'string', |  | ||||||
|                     programIdIndex: 'number', |  | ||||||
|                   }), |  | ||||||
|                 ]), |  | ||||||
|               ]), |  | ||||||
|               recentBlockhash: 'string', |  | ||||||
|             }), |  | ||||||
|           }), |  | ||||||
|           meta: struct.union([ |  | ||||||
|             'null', |  | ||||||
|             struct.pick({ |  | ||||||
|               err: TransactionErrorResult, |  | ||||||
|               fee: 'number', |  | ||||||
|               preBalances: struct.array(['number']), |  | ||||||
|               postBalances: struct.array(['number']), |  | ||||||
|             }), |  | ||||||
|           ]), |  | ||||||
|         }), |         }), | ||||||
|       ]), |       ]), | ||||||
|       rewards: struct.union([ |       rewards: struct.union([ | ||||||
| @@ -577,6 +613,20 @@ export const GetConfirmedBlockRpcResult = jsonRpcResult( | |||||||
|   ]), |   ]), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Expected JSON RPC response for the "getConfirmedTransaction" message | ||||||
|  |  */ | ||||||
|  | const GetConfirmedTransactionRpcResult = jsonRpcResult( | ||||||
|  |   struct.union([ | ||||||
|  |     'null', | ||||||
|  |     struct({ | ||||||
|  |       slot: 'number', | ||||||
|  |       transaction: ConfirmedTransactionResult, | ||||||
|  |       meta: ConfirmedTransactionMetaResult, | ||||||
|  |     }), | ||||||
|  |   ]), | ||||||
|  | ); | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Expected JSON RPC response for the "getRecentBlockhash" message |  * Expected JSON RPC response for the "getRecentBlockhash" message | ||||||
|  */ |  */ | ||||||
| @@ -1266,6 +1316,59 @@ export class Connection { | |||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Fetch a transaction details for a confirmed transaction | ||||||
|  |    */ | ||||||
|  |   async getConfirmedTransaction( | ||||||
|  |     signature: TransactionSignature, | ||||||
|  |   ): Promise<ConfirmedTransaction | null> { | ||||||
|  |     const unsafeRes = await this._rpcRequest('getConfirmedTransaction', [ | ||||||
|  |       signature, | ||||||
|  |     ]); | ||||||
|  |     const {result, error} = GetConfirmedTransactionRpcResult(unsafeRes); | ||||||
|  |     if (error) { | ||||||
|  |       throw new Error('failed to get confirmed transaction: ' + error.message); | ||||||
|  |     } | ||||||
|  |     assert(typeof result !== 'undefined'); | ||||||
|  |     if (result === null) { | ||||||
|  |       return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |       slot: result.slot, | ||||||
|  |       transaction: Transaction.fromRpcResult(result.transaction), | ||||||
|  |       meta: result.meta, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * Fetch a list of all the confirmed signatures for transactions involving an address | ||||||
|  |    * within a specified slot range. Max range allowed is 10,000 slots. | ||||||
|  |    * | ||||||
|  |    * @param address queried address | ||||||
|  |    * @param startSlot start slot, inclusive | ||||||
|  |    * @param endSlot end slot, inclusive | ||||||
|  |    */ | ||||||
|  |   async getConfirmedSignaturesForAddress( | ||||||
|  |     address: PublicKey, | ||||||
|  |     startSlot: number, | ||||||
|  |     endSlot: number, | ||||||
|  |   ): Promise<Array<TransactionSignature>> { | ||||||
|  |     const unsafeRes = await this._rpcRequest( | ||||||
|  |       'getConfirmedSignaturesForAddress', | ||||||
|  |       [address.toBase58(), startSlot, endSlot], | ||||||
|  |     ); | ||||||
|  |     const result = GetConfirmedSignaturesForAddressRpcResult(unsafeRes); | ||||||
|  |     if (result.error) { | ||||||
|  |       throw new Error( | ||||||
|  |         'failed to get confirmed signatures for address: ' + | ||||||
|  |           result.error.message, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     assert(typeof result.result !== 'undefined'); | ||||||
|  |     return result.result; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * Fetch the contents of a Nonce account from the cluster, return with context |    * Fetch the contents of a Nonce account from the cluster, return with context | ||||||
|    */ |    */ | ||||||
|   | |||||||
| @@ -1,10 +1,13 @@ | |||||||
| // @flow | // @flow | ||||||
|  | import bs58 from 'bs58'; | ||||||
|  |  | ||||||
| import { | import { | ||||||
|   Account, |   Account, | ||||||
|   Connection, |   Connection, | ||||||
|   SystemProgram, |   SystemProgram, | ||||||
|   sendAndConfirmTransaction, |   sendAndConfirmTransaction, | ||||||
|   LAMPORTS_PER_SOL, |   LAMPORTS_PER_SOL, | ||||||
|  |   PublicKey, | ||||||
| } from '../src'; | } from '../src'; | ||||||
| import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from '../src/timing'; | import {DEFAULT_TICKS_PER_SLOT, NUM_TICKS_PER_SECOND} from '../src/timing'; | ||||||
| import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch'; | import {mockRpc, mockRpcEnabled} from './__mocks__/node-fetch'; | ||||||
| @@ -570,6 +573,331 @@ test('get minimum balance for rent exemption', async () => { | |||||||
|   expect(count).toBeGreaterThanOrEqual(0); |   expect(count).toBeGreaterThanOrEqual(0); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | test('get confirmed signatures for address', async () => { | ||||||
|  |   const connection = new Connection(url); | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getSlot', | ||||||
|  |       params: [], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: 1, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   while ((await connection.getSlot()) <= 0) { | ||||||
|  |     continue; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedBlock', | ||||||
|  |       params: [1], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: { | ||||||
|  |         blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', | ||||||
|  |         previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', | ||||||
|  |         parentSlot: 0, | ||||||
|  |         transactions: [ | ||||||
|  |           { | ||||||
|  |             meta: { | ||||||
|  |               fee: 10000, | ||||||
|  |               postBalances: [499260347380, 15298080, 1, 1, 1], | ||||||
|  |               preBalances: [499260357380, 15298080, 1, 1, 1], | ||||||
|  |               status: {Ok: null}, | ||||||
|  |               err: null, | ||||||
|  |             }, | ||||||
|  |             transaction: { | ||||||
|  |               message: { | ||||||
|  |                 accountKeys: [ | ||||||
|  |                   'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', | ||||||
|  |                   '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', | ||||||
|  |                   'SysvarS1otHashes111111111111111111111111111', | ||||||
|  |                   'SysvarC1ock11111111111111111111111111111111', | ||||||
|  |                   'Vote111111111111111111111111111111111111111', | ||||||
|  |                 ], | ||||||
|  |                 header: { | ||||||
|  |                   numReadonlySignedAccounts: 0, | ||||||
|  |                   numReadonlyUnsignedAccounts: 3, | ||||||
|  |                   numRequiredSignatures: 2, | ||||||
|  |                 }, | ||||||
|  |                 instructions: [ | ||||||
|  |                   { | ||||||
|  |                     accounts: [1, 2, 3], | ||||||
|  |                     data: | ||||||
|  |                       '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', | ||||||
|  |                     programIdIndex: 4, | ||||||
|  |                   }, | ||||||
|  |                 ], | ||||||
|  |                 recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', | ||||||
|  |               }, | ||||||
|  |               signatures: [ | ||||||
|  |                 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', | ||||||
|  |                 '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', | ||||||
|  |               ], | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   // Find a block that has a transaction, usually Block 1 | ||||||
|  |   let slot = 0; | ||||||
|  |   let address: ?PublicKey; | ||||||
|  |   let expectedSignature: ?string; | ||||||
|  |   while (!address || !expectedSignature) { | ||||||
|  |     slot++; | ||||||
|  |     const block = await connection.getConfirmedBlock(slot); | ||||||
|  |     if (block.transactions.length > 0) { | ||||||
|  |       const { | ||||||
|  |         signature, | ||||||
|  |         publicKey, | ||||||
|  |       } = block.transactions[0].transaction.signatures[0]; | ||||||
|  |       if (signature) { | ||||||
|  |         address = publicKey; | ||||||
|  |         expectedSignature = bs58.encode(signature); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedSignaturesForAddress', | ||||||
|  |       params: [address.toBase58(), slot, slot + 1], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: [expectedSignature], | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   const confirmedSignatures = await connection.getConfirmedSignaturesForAddress( | ||||||
|  |     address, | ||||||
|  |     slot, | ||||||
|  |     slot + 1, | ||||||
|  |   ); | ||||||
|  |   expect(confirmedSignatures.includes(expectedSignature)).toBe(true); | ||||||
|  |  | ||||||
|  |   const badSlot = Number.MAX_SAFE_INTEGER - 1; | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedSignaturesForAddress', | ||||||
|  |       params: [address.toBase58(), badSlot, badSlot + 1], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: [], | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   const emptySignatures = await connection.getConfirmedSignaturesForAddress( | ||||||
|  |     address, | ||||||
|  |     badSlot, | ||||||
|  |     badSlot + 1, | ||||||
|  |   ); | ||||||
|  |   expect(emptySignatures.length).toBe(0); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | test('get confirmed transaction', async () => { | ||||||
|  |   const connection = new Connection(url); | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getSlot', | ||||||
|  |       params: [], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: 1, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   while ((await connection.getSlot()) <= 0) { | ||||||
|  |     continue; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedBlock', | ||||||
|  |       params: [1], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: { | ||||||
|  |         blockhash: '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', | ||||||
|  |         previousBlockhash: 'H5nJ91eGag3B5ZSRHZ7zG5ZwXJ6ywCt2hyR8xCsV7xMo', | ||||||
|  |         parentSlot: 0, | ||||||
|  |         transactions: [ | ||||||
|  |           { | ||||||
|  |             meta: { | ||||||
|  |               fee: 10000, | ||||||
|  |               postBalances: [499260347380, 15298080, 1, 1, 1], | ||||||
|  |               preBalances: [499260357380, 15298080, 1, 1, 1], | ||||||
|  |               status: {Ok: null}, | ||||||
|  |               err: null, | ||||||
|  |             }, | ||||||
|  |             transaction: { | ||||||
|  |               message: { | ||||||
|  |                 accountKeys: [ | ||||||
|  |                   'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', | ||||||
|  |                   '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', | ||||||
|  |                   'SysvarS1otHashes111111111111111111111111111', | ||||||
|  |                   'SysvarC1ock11111111111111111111111111111111', | ||||||
|  |                   'Vote111111111111111111111111111111111111111', | ||||||
|  |                 ], | ||||||
|  |                 header: { | ||||||
|  |                   numReadonlySignedAccounts: 0, | ||||||
|  |                   numReadonlyUnsignedAccounts: 3, | ||||||
|  |                   numRequiredSignatures: 2, | ||||||
|  |                 }, | ||||||
|  |                 instructions: [ | ||||||
|  |                   { | ||||||
|  |                     accounts: [1, 2, 3], | ||||||
|  |                     data: | ||||||
|  |                       '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', | ||||||
|  |                     programIdIndex: 4, | ||||||
|  |                   }, | ||||||
|  |                 ], | ||||||
|  |                 recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', | ||||||
|  |               }, | ||||||
|  |               signatures: [ | ||||||
|  |                 'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', | ||||||
|  |                 '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', | ||||||
|  |               ], | ||||||
|  |             }, | ||||||
|  |           }, | ||||||
|  |         ], | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   // Find a block that has a transaction, usually Block 1 | ||||||
|  |   let slot = 0; | ||||||
|  |   let confirmedTransaction: ?string; | ||||||
|  |   while (!confirmedTransaction) { | ||||||
|  |     slot++; | ||||||
|  |     const block = await connection.getConfirmedBlock(slot); | ||||||
|  |     for (const tx of block.transactions) { | ||||||
|  |       if (tx.transaction.signature) { | ||||||
|  |         confirmedTransaction = bs58.encode(tx.transaction.signature); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedTransaction', | ||||||
|  |       params: [confirmedTransaction], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: { | ||||||
|  |         slot, | ||||||
|  |         transaction: { | ||||||
|  |           message: { | ||||||
|  |             accountKeys: [ | ||||||
|  |               'va12u4o9DipLEB2z4fuoHszroq1U9NcAB9aooFDPJSf', | ||||||
|  |               '57zQNBZBEiHsCZFqsaY6h176ioXy5MsSLmcvHkEyaLGy', | ||||||
|  |               'SysvarS1otHashes111111111111111111111111111', | ||||||
|  |               'SysvarC1ock11111111111111111111111111111111', | ||||||
|  |               'Vote111111111111111111111111111111111111111', | ||||||
|  |             ], | ||||||
|  |             header: { | ||||||
|  |               numReadonlySignedAccounts: 0, | ||||||
|  |               numReadonlyUnsignedAccounts: 3, | ||||||
|  |               numRequiredSignatures: 2, | ||||||
|  |             }, | ||||||
|  |             instructions: [ | ||||||
|  |               { | ||||||
|  |                 accounts: [1, 2, 3], | ||||||
|  |                 data: | ||||||
|  |                   '37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7', | ||||||
|  |                 programIdIndex: 4, | ||||||
|  |               }, | ||||||
|  |             ], | ||||||
|  |             recentBlockhash: 'GeyAFFRY3WGpmam2hbgrKw4rbU2RKzfVLm5QLSeZwTZE', | ||||||
|  |           }, | ||||||
|  |           signatures: [ | ||||||
|  |             'w2Zeq8YkpyB463DttvfzARD7k9ZxGEwbsEw4boEK7jDp3pfoxZbTdLFSsEPhzXhpCcjGi2kHtHFobgX49MMhbWt', | ||||||
|  |             '4oCEqwGrMdBeMxpzuWiukCYqSfV4DsSKXSiVVCh1iJ6pS772X7y219JZP3mgqBz5PhsvprpKyhzChjYc3VSBQXzG', | ||||||
|  |           ], | ||||||
|  |         }, | ||||||
|  |         meta: { | ||||||
|  |           fee: 10000, | ||||||
|  |           postBalances: [499260347380, 15298080, 1, 1, 1], | ||||||
|  |           preBalances: [499260357380, 15298080, 1, 1, 1], | ||||||
|  |           status: {Ok: null}, | ||||||
|  |           err: null, | ||||||
|  |         }, | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   const result = await connection.getConfirmedTransaction(confirmedTransaction); | ||||||
|  |  | ||||||
|  |   if (!result) { | ||||||
|  |     expect(result).toBeDefined(); | ||||||
|  |     expect(result).not.toBeNull(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (result.transaction.signature === null) { | ||||||
|  |     expect(result.transaction.signature).not.toBeNull(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   const resultSignature = bs58.encode(result.transaction.signature); | ||||||
|  |   expect(resultSignature).toEqual(confirmedTransaction); | ||||||
|  |  | ||||||
|  |   const newAddress = new Account().publicKey; | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'requestAirdrop', | ||||||
|  |       params: [newAddress.toBase58(), 1, {commitment: 'recent'}], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: | ||||||
|  |         '1WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk', | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   const recentSignature = await connection.requestAirdrop( | ||||||
|  |     newAddress, | ||||||
|  |     1, | ||||||
|  |     'recent', | ||||||
|  |   ); | ||||||
|  |   mockRpc.push([ | ||||||
|  |     url, | ||||||
|  |     { | ||||||
|  |       method: 'getConfirmedTransaction', | ||||||
|  |       params: [recentSignature], | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       error: null, | ||||||
|  |       result: null, | ||||||
|  |     }, | ||||||
|  |   ]); | ||||||
|  |  | ||||||
|  |   const nullResponse = await connection.getConfirmedTransaction( | ||||||
|  |     recentSignature, | ||||||
|  |   ); | ||||||
|  |   expect(nullResponse).toBeNull(); | ||||||
|  | }); | ||||||
|  |  | ||||||
| test('get confirmed block', async () => { | test('get confirmed block', async () => { | ||||||
|   const connection = new Connection(url); |   const connection = new Connection(url); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user