feat: update getSignatureStatus

This commit is contained in:
Justin Starry
2020-03-23 23:01:12 +08:00
committed by Michael Vines
parent ac8660b2e9
commit 1c31e527e2
7 changed files with 152 additions and 26 deletions

11
web3.js/module.d.ts vendored
View File

@ -48,6 +48,11 @@ declare module '@solana/web3.js' {
export type SignatureStatusResult = SignatureSuccess | TransactionError; export type SignatureStatusResult = SignatureSuccess | TransactionError;
export type SignatureStatus = {
slot: number;
status: SignatureSuccess | TransactionError;
};
export type BlockhashAndFeeCalculator = { export type BlockhashAndFeeCalculator = {
blockhash: Blockhash; blockhash: Blockhash;
feeCalculator: FeeCalculator; feeCalculator: FeeCalculator;
@ -183,7 +188,11 @@ declare module '@solana/web3.js' {
getSignatureStatus( getSignatureStatus(
signature: TransactionSignature, signature: TransactionSignature,
commitment?: Commitment, commitment?: Commitment,
): Promise<SignatureSuccess | TransactionError | null>; ): Promise<SignatureStatus | null>;
getSignatureStatusBatch(
signatures: Array<TransactionSignature>,
commitment?: Commitment,
): Promise<Array<SignatureStatus | null>>;
getTransactionCount(commitment?: Commitment): Promise<number>; getTransactionCount(commitment?: Commitment): Promise<number>;
getTotalSupply(commitment?: Commitment): Promise<number>; getTotalSupply(commitment?: Commitment): Promise<number>;
getVersion(): Promise<Version>; getVersion(): Promise<Version>;

View File

@ -63,6 +63,11 @@ declare module '@solana/web3.js' {
| SignatureSuccess | SignatureSuccess
| TransactionError; | TransactionError;
declare export type SignatureStatus = {
slot: number,
status: SignatureSuccess | TransactionError,
};
declare export type BlockhashAndFeeCalculator = { declare export type BlockhashAndFeeCalculator = {
blockhash: Blockhash, blockhash: Blockhash,
feeCalculator: FeeCalculator, feeCalculator: FeeCalculator,
@ -198,7 +203,11 @@ declare module '@solana/web3.js' {
getSignatureStatus( getSignatureStatus(
signature: TransactionSignature, signature: TransactionSignature,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<SignatureSuccess | TransactionError | null>; ): Promise<SignatureStatus | null>;
getSignatureStatusBatch(
signatures: Array<TransactionSignature>,
commitment: ?Commitment,
): Promise<Array<SignatureStatus | null>>;
getTransactionCount(commitment: ?Commitment): Promise<number>; getTransactionCount(commitment: ?Commitment): Promise<number>;
getTotalSupply(commitment: ?Commitment): Promise<number>; getTotalSupply(commitment: ?Commitment): Promise<number>;
getVersion(): Promise<Version>; getVersion(): Promise<Version>;

View File

@ -452,7 +452,15 @@ const GetVoteAccounts = jsonRpcResult(
* Expected JSON RPC response for the "getSignatureStatus" message * Expected JSON RPC response for the "getSignatureStatus" message
*/ */
const GetSignatureStatusRpcResult = jsonRpcResult( const GetSignatureStatusRpcResult = jsonRpcResult(
struct.union(['null', SignatureStatusResult]), struct.array([
struct.union([
'null',
struct({
slot: 'number',
status: SignatureStatusResult,
}),
]),
]),
); );
/** /**
@ -660,6 +668,18 @@ export type TransactionError = {|
Err: Object, Err: Object,
|}; |};
/**
* Signature status
*
* @typedef {Object} SignatureStatus
* @property {number} slot when the transaction was processed
* @property {SignatureStatus | TransactionError} status
*/
export type SignatureStatus = {
slot: number,
status: SignatureSuccess | TransactionError,
};
/** /**
* A connection to a fullnode JSON RPC endpoint * A connection to a fullnode JSON RPC endpoint
*/ */
@ -944,8 +964,20 @@ export class Connection {
async getSignatureStatus( async getSignatureStatus(
signature: TransactionSignature, signature: TransactionSignature,
commitment: ?Commitment, commitment: ?Commitment,
): Promise<SignatureSuccess | TransactionError | null> { ): Promise<SignatureStatus | null> {
const args = this._argsWithCommitment([signature], commitment); const res = await this.getSignatureStatusBatch([signature], commitment);
assert(res.length === 1);
return res[0];
}
/**
* Fetch the current status of a signature
*/
async getSignatureStatusBatch(
signatures: Array<TransactionSignature>,
commitment: ?Commitment,
): Promise<Array<SignatureStatus | null>> {
const args = this._argsWithCommitment([signatures], commitment);
const unsafeRes = await this._rpcRequest('getSignatureStatus', args); const unsafeRes = await this._rpcRequest('getSignatureStatus', args);
const res = GetSignatureStatusRpcResult(unsafeRes); const res = GetSignatureStatusRpcResult(unsafeRes);
if (res.error) { if (res.error) {

View File

@ -39,7 +39,7 @@ export async function sendAndConfirmRawTransaction(
} }
} }
if (status && 'Ok' in status) { if (status && status.status && 'Ok' in status.status) {
return signature; return signature;
} }

View File

@ -65,7 +65,7 @@ async function _sendAndConfirmTransaction(
await sleep((500 * DEFAULT_TICKS_PER_SLOT) / NUM_TICKS_PER_SECOND); await sleep((500 * DEFAULT_TICKS_PER_SLOT) / NUM_TICKS_PER_SECOND);
} }
if (status && 'Ok' in status) { if (status && 'Ok' in status.status) {
break; break;
} }
if (--sendRetries <= 0) { if (--sendRetries <= 0) {
@ -77,7 +77,7 @@ async function _sendAndConfirmTransaction(
); );
} }
if (status && status.Err && !('AccountInUse' in status.Err)) { if (status && status.status.Err && !('AccountInUse' in status.status.Err)) {
throw new Error( throw new Error(
`Transaction ${signature} failed (${JSON.stringify(status)})`, `Transaction ${signature} failed (${JSON.stringify(status)})`,
); );

View File

@ -100,13 +100,20 @@ test('get program accounts', async () => {
{ {
method: 'getSignatureStatus', method: 'getSignatureStatus',
params: [ params: [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk', [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
],
{commitment: 'recent'}, {commitment: 'recent'},
], ],
}, },
{ {
error: null, error: null,
result: {Ok: null}, result: [
{
slot: 0,
status: {Ok: null},
},
],
}, },
]); ]);
let transaction = SystemProgram.assign({ let transaction = SystemProgram.assign({
@ -131,13 +138,20 @@ test('get program accounts', async () => {
{ {
method: 'getSignatureStatus', method: 'getSignatureStatus',
params: [ params: [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk', [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
],
{commitment: 'recent'}, {commitment: 'recent'},
], ],
}, },
{ {
error: null, error: null,
result: {Ok: null}, result: [
{
slot: 0,
status: {Ok: null},
},
],
}, },
]); ]);
transaction = SystemProgram.assign({ transaction = SystemProgram.assign({
@ -471,7 +485,7 @@ test('confirm transaction - error', async () => {
url, url,
{ {
method: 'getSignatureStatus', method: 'getSignatureStatus',
params: [badTransactionSignature], params: [[badTransactionSignature]],
}, },
errorResponse, errorResponse,
]); ]);
@ -1011,18 +1025,64 @@ test('transaction', async () => {
{ {
method: 'getSignatureStatus', method: 'getSignatureStatus',
params: [ params: [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk', [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
],
{commitment: 'recent'}, {commitment: 'recent'},
], ],
}, },
{ {
error: null, error: null,
result: {Ok: null}, result: [
{
slot: 0,
status: {Ok: null},
},
],
}, },
]); ]);
await expect(connection.getSignatureStatus(signature)).resolves.toEqual({
Ok: null, const response = await connection.getSignatureStatus(signature);
}); if (response !== null) {
expect(typeof response.slot).toEqual('number');
expect(response.status).toEqual({Ok: null});
} else {
expect(response).not.toBeNull();
}
const unprocessedSignature =
'8WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk';
mockRpc.push([
url,
{
method: 'getSignatureStatus',
params: [
[
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
unprocessedSignature,
],
{commitment: 'recent'},
],
},
{
error: null,
result: [
{
slot: 0,
status: {Ok: null},
},
null,
],
},
]);
const responses = await connection.getSignatureStatusBatch([
signature,
unprocessedSignature,
]);
expect(responses.length).toEqual(2);
expect(responses[0]).toEqual(response);
expect(responses[1]).toBeNull();
mockRpc.push([ mockRpc.push([
url, url,
@ -1120,9 +1180,14 @@ test('multi-instruction transaction', async () => {
expect(++i).toBeLessThan(10); expect(++i).toBeLessThan(10);
await sleep(500); await sleep(500);
} }
await expect(connection.getSignatureStatus(signature)).resolves.toEqual({
Ok: null, const response = await connection.getSignatureStatus(signature);
}); if (response !== null) {
expect(typeof response.slot).toEqual('number');
expect(response.status).toEqual({Ok: null});
} else {
expect(response).not.toBeNull();
}
// accountFrom may have less than LAMPORTS_PER_SOL due to transaction fees // accountFrom may have less than LAMPORTS_PER_SOL due to transaction fees
expect(await connection.getBalance(accountFrom.publicKey)).toBeGreaterThan(0); expect(await connection.getBalance(accountFrom.publicKey)).toBeGreaterThan(0);

View File

@ -148,18 +148,29 @@ test('transaction-payer', async () => {
{ {
method: 'getSignatureStatus', method: 'getSignatureStatus',
params: [ params: [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk', [
'3WE5w4B7v59x6qjyC4FbG2FEKYKQfvsJwqSxNVmtMjT8TQ31hsZieDHcSgqzxiAoTL56n2w5TncjqEKjLhtF4Vk',
],
{commitment: 'recent'}, {commitment: 'recent'},
], ],
}, },
{ {
error: null, error: null,
result: {Ok: null}, result: [
{
slot: 0,
status: {Ok: null},
},
],
}, },
]); ]);
await expect(connection.getSignatureStatus(signature)).resolves.toEqual({ const response = await connection.getSignatureStatus(signature);
Ok: null, if (response !== null) {
}); expect(typeof response.slot).toEqual('number');
expect(response.status).toEqual({Ok: null});
} else {
expect(response).not.toBeNull();
}
mockRpc.push([ mockRpc.push([
url, url,