diff --git a/web3.js/module.d.ts b/web3.js/module.d.ts index 865c951611..ba04110fe7 100644 --- a/web3.js/module.d.ts +++ b/web3.js/module.d.ts @@ -48,11 +48,10 @@ declare module '@solana/web3.js' { export type Commitment = 'max' | 'recent'; - export type SignatureStatusResult = SignatureSuccess | TransactionError; - export type SignatureStatus = { slot: number; status: SignatureSuccess | TransactionError; + confirmations: number | null; }; export type BlockhashAndFeeCalculator = { @@ -90,7 +89,7 @@ declare module '@solana/web3.js' { fee: number; preBalances: Array; postBalances: Array; - status?: SignatureStatusResult; + status?: SignatureSuccess | TransactionError; }; }>; }; @@ -127,7 +126,7 @@ declare module '@solana/web3.js' { ) => void; export type SlotChangeCallback = (slotInfo: SlotInfo) => void; export type SignatureResultCallback = ( - signatureResult: SignatureStatusResult, + signatureResult: SignatureSuccess | TransactionError, context: Context, ) => void; @@ -195,11 +194,11 @@ declare module '@solana/web3.js' { getSignatureStatus( signature: TransactionSignature, commitment?: Commitment, - ): Promise; + ): Promise>; getSignatureStatusBatch( signatures: Array, commitment?: Commitment, - ): Promise>; + ): Promise>>; getTransactionCount(commitment?: Commitment): Promise; getTotalSupply(commitment?: Commitment): Promise; getVersion(): Promise; diff --git a/web3.js/module.flow.js b/web3.js/module.flow.js index 3f005a3f19..b5c707e809 100644 --- a/web3.js/module.flow.js +++ b/web3.js/module.flow.js @@ -61,13 +61,10 @@ declare module '@solana/web3.js' { declare export type Commitment = 'max' | 'recent'; - declare export type SignatureStatusResult = - | SignatureSuccess - | TransactionError; - declare export type SignatureStatus = { slot: number, status: SignatureSuccess | TransactionError, + confirmations: number | null, }; declare export type BlockhashAndFeeCalculator = { @@ -105,7 +102,7 @@ declare module '@solana/web3.js' { fee: number, preBalances: Array, postBalances: Array, - status: ?SignatureStatusResult, + status: SignatureSuccess | TransactionError | null, }, }>, }; @@ -142,7 +139,7 @@ declare module '@solana/web3.js' { ) => void; declare type SlotChangeCallback = (slotInfo: SlotInfo) => void; declare type SignatureResultCallback = ( - signatureResult: SignatureStatusResult, + signatureResult: SignatureSuccess | TransactionError, context: Context, ) => void; @@ -210,11 +207,11 @@ declare module '@solana/web3.js' { getSignatureStatus( signature: TransactionSignature, commitment: ?Commitment, - ): Promise; + ): Promise>; getSignatureStatusBatch( signatures: Array, commitment: ?Commitment, - ): Promise>; + ): Promise>>; getTransactionCount(commitment: ?Commitment): Promise; getTotalSupply(commitment: ?Commitment): Promise; getVersion(): Promise; diff --git a/web3.js/src/connection.js b/web3.js/src/connection.js index 025f98d4c2..8f10b34f58 100644 --- a/web3.js/src/connection.js +++ b/web3.js/src/connection.js @@ -241,7 +241,7 @@ type ConfirmedBlock = { fee: number, preBalances: Array, postBalances: Array, - status?: SignatureStatusResult, + status?: SignatureSuccess | TransactionError, }, }>, rewards: Array<{ @@ -471,12 +471,13 @@ const GetVoteAccounts = jsonRpcResult( /** * Expected JSON RPC response for the "getSignatureStatus" message */ -const GetSignatureStatusRpcResult = jsonRpcResult( +const GetSignatureStatusRpcResult = jsonRpcResultAndContext( struct.array([ struct.union([ 'null', struct({ slot: 'number', + confirmations: struct.union(['number', 'null']), status: SignatureStatusResult, }), ]), @@ -662,7 +663,7 @@ type SlotSubscriptionInfo = { * Callback function for signature notifications */ export type SignatureResultCallback = ( - signatureResult: SignatureStatusResult, + signatureResult: SignatureSuccess | TransactionError, context: Context, ) => void; @@ -698,10 +699,12 @@ export type TransactionError = {| * * @typedef {Object} SignatureStatus * @property {number} slot when the transaction was processed - * @property {SignatureStatus | TransactionError} status + * @property {number | null} confirmations the number of blocks that have been confirmed and voted on in the fork containing `slot` (TODO) + * @property {SignatureStatus | TransactionError} status success or error */ export type SignatureStatus = { slot: number, + confirmations: number | null, status: SignatureSuccess | TransactionError, }; @@ -989,10 +992,13 @@ export class Connection { async getSignatureStatus( signature: TransactionSignature, commitment: ?Commitment, - ): Promise { - const res = await this.getSignatureStatusBatch([signature], commitment); - assert(res.length === 1); - return res[0]; + ): Promise> { + const {context, value} = await this.getSignatureStatusBatch( + [signature], + commitment, + ); + assert(value.length === 1); + return {context, value: value[0]}; } /** @@ -1001,7 +1007,7 @@ export class Connection { async getSignatureStatusBatch( signatures: Array, commitment: ?Commitment, - ): Promise> { + ): Promise>> { const args = this._argsWithCommitment([signatures], commitment); const unsafeRes = await this._rpcRequest('getSignatureStatus', args); const res = GetSignatureStatusRpcResult(unsafeRes); diff --git a/web3.js/src/util/send-and-confirm-raw-transaction.js b/web3.js/src/util/send-and-confirm-raw-transaction.js index d4c05b7dba..be3b6d28d0 100644 --- a/web3.js/src/util/send-and-confirm-raw-transaction.js +++ b/web3.js/src/util/send-and-confirm-raw-transaction.js @@ -21,7 +21,7 @@ export async function sendAndConfirmRawTransaction( let status = null; let statusRetries = 6; for (;;) { - status = await connection.getSignatureStatus(signature, commitment); + status = (await connection.getSignatureStatus(signature, commitment)).value; if (status) { break; } diff --git a/web3.js/src/util/send-and-confirm-transaction.js b/web3.js/src/util/send-and-confirm-transaction.js index 4c82a1e0b2..aebf6996e8 100644 --- a/web3.js/src/util/send-and-confirm-transaction.js +++ b/web3.js/src/util/send-and-confirm-transaction.js @@ -53,7 +53,8 @@ async function _sendAndConfirmTransaction( let status = null; let statusRetries = 6; for (;;) { - status = await connection.getSignatureStatus(signature, commitment); + status = (await connection.getSignatureStatus(signature, commitment)) + .value; if (status) { break; } diff --git a/web3.js/test/connection.test.js b/web3.js/test/connection.test.js index 048b777066..9d3d3f1f86 100644 --- a/web3.js/test/connection.test.js +++ b/web3.js/test/connection.test.js @@ -108,12 +108,18 @@ test('get program accounts', async () => { }, { error: null, - result: [ - { - slot: 0, - status: {Ok: null}, + result: { + context: { + slot: 11, }, - ], + value: [ + { + slot: 0, + confirmations: 11, + status: {Ok: null}, + }, + ], + }, }, ]); let transaction = SystemProgram.assign({ @@ -146,12 +152,18 @@ test('get program accounts', async () => { }, { error: null, - result: [ - { - slot: 0, - status: {Ok: null}, + result: { + context: { + slot: 11, }, - ], + value: [ + { + slot: 0, + confirmations: 11, + status: {Ok: null}, + }, + ], + }, }, ]); transaction = SystemProgram.assign({ @@ -1009,6 +1021,9 @@ test('transaction', async () => { }, ]); + // Wait for one confirmation + await sleep(500); + let i = 0; for (;;) { if (await connection.confirmTransaction(signature)) { @@ -1033,23 +1048,37 @@ test('transaction', async () => { }, { error: null, - result: [ - { - slot: 0, - status: {Ok: null}, + result: { + context: { + slot: 11, }, - ], + value: [ + { + slot: 0, + confirmations: 11, + status: {Ok: null}, + }, + ], + }, }, ]); - const response = await connection.getSignatureStatus(signature); - if (response !== null) { - expect(typeof response.slot).toEqual('number'); - expect(response.status).toEqual({Ok: null}); - } else { + const response = (await connection.getSignatureStatus(signature)).value; + if (response === null) { expect(response).not.toBeNull(); + return; } + const responseConfirmations = response.confirmations; + if (typeof responseConfirmations !== 'number') { + expect(typeof responseConfirmations).toEqual('number'); + return; + } + + expect(response.status).toEqual({Ok: null}); + expect(response.slot).toBeGreaterThanOrEqual(0); + expect(responseConfirmations).toBeGreaterThan(0); + const unprocessedSignature = '8WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk'; mockRpc.push([ @@ -1066,24 +1095,47 @@ test('transaction', async () => { }, { error: null, - result: [ - { - slot: 0, - status: {Ok: null}, + result: { + context: { + slot: 11, }, - null, - ], + value: [ + { + slot: 0, + confirmations: 11, + status: {Ok: null}, + }, + null, + ], + }, }, ]); - const responses = await connection.getSignatureStatusBatch([ - signature, - unprocessedSignature, - ]); + const responses = ( + await connection.getSignatureStatusBatch([signature, unprocessedSignature]) + ).value; expect(responses.length).toEqual(2); - expect(responses[0]).toEqual(response); + + const firstResponse = responses[0]; expect(responses[1]).toBeNull(); + if (firstResponse === null) { + expect(firstResponse).not.toBeNull(); + return; + } + + expect(firstResponse.slot).toBeGreaterThanOrEqual(response.slot); + expect(firstResponse.status).toEqual(response.status); + + if (typeof firstResponse.confirmations !== 'number') { + expect(typeof firstResponse.confirmations).toEqual('number'); + return; + } + + expect(firstResponse.confirmations).toBeGreaterThanOrEqual( + responseConfirmations, + ); + mockRpc.push([ url, { @@ -1181,7 +1233,7 @@ test('multi-instruction transaction', async () => { await sleep(500); } - const response = await connection.getSignatureStatus(signature); + const response = (await connection.getSignatureStatus(signature)).value; if (response !== null) { expect(typeof response.slot).toEqual('number'); expect(response.status).toEqual({Ok: null}); diff --git a/web3.js/test/transaction-payer.test.js b/web3.js/test/transaction-payer.test.js index 71ee5a4f13..74520d469e 100644 --- a/web3.js/test/transaction-payer.test.js +++ b/web3.js/test/transaction-payer.test.js @@ -156,20 +156,26 @@ test('transaction-payer', async () => { }, { error: null, - result: [ - { - slot: 0, - status: {Ok: null}, + result: { + context: { + slot: 11, }, - ], + value: [ + { + slot: 0, + confirmations: 11, + status: {Ok: null}, + }, + ], + }, }, ]); - const response = await connection.getSignatureStatus(signature); - if (response !== null) { - expect(typeof response.slot).toEqual('number'); - expect(response.status).toEqual({Ok: null}); + const {value} = await connection.getSignatureStatus(signature); + if (value !== null) { + expect(typeof value.slot).toEqual('number'); + expect(value.status).toEqual({Ok: null}); } else { - expect(response).not.toBeNull(); + expect(value).not.toBeNull(); } mockRpc.push([