fix: retry transactions on AccountInUse errors
This commit is contained in:
@ -41,7 +41,11 @@ declare module '@solana/web3.js' {
|
|||||||
userdata: Buffer,
|
userdata: Buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
declare export type SignatureStatus = 'Confirmed' | 'SignatureNotFound' | 'ProgramRuntimeError' | 'GenericFailure';
|
declare export type SignatureStatus = 'Confirmed'
|
||||||
|
| 'AccountInUse'
|
||||||
|
| 'SignatureNotFound'
|
||||||
|
| 'ProgramRuntimeError'
|
||||||
|
| 'GenericFailure';
|
||||||
|
|
||||||
declare export class Connection {
|
declare export class Connection {
|
||||||
constructor(endpoint: string): Connection;
|
constructor(endpoint: string): Connection;
|
||||||
|
@ -101,10 +101,11 @@ const ConfirmTransactionRpcResult = jsonRpcResult('boolean');
|
|||||||
* Expected JSON RPC response for the "getSignatureStatus" message
|
* Expected JSON RPC response for the "getSignatureStatus" message
|
||||||
*/
|
*/
|
||||||
const GetSignatureStatusRpcResult = jsonRpcResult(struct.enum([
|
const GetSignatureStatusRpcResult = jsonRpcResult(struct.enum([
|
||||||
|
'AccountInUse',
|
||||||
'Confirmed',
|
'Confirmed',
|
||||||
'SignatureNotFound',
|
|
||||||
'ProgramRuntimeError',
|
|
||||||
'GenericFailure',
|
'GenericFailure',
|
||||||
|
'ProgramRuntimeError',
|
||||||
|
'SignatureNotFound',
|
||||||
]));
|
]));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,7 +153,11 @@ type AccountInfo = {
|
|||||||
*
|
*
|
||||||
* @typedef {string} SignatureStatus
|
* @typedef {string} SignatureStatus
|
||||||
*/
|
*/
|
||||||
export type SignatureStatus = 'Confirmed' | 'SignatureNotFound' | 'ProgramRuntimeError' | 'GenericFailure';
|
export type SignatureStatus = 'Confirmed'
|
||||||
|
| 'AccountInUse'
|
||||||
|
| 'SignatureNotFound'
|
||||||
|
| 'ProgramRuntimeError'
|
||||||
|
| 'GenericFailure';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A connection to a fullnode JSON RPC endpoint
|
* A connection to a fullnode JSON RPC endpoint
|
||||||
|
@ -15,31 +15,36 @@ export async function sendAndConfirmTransaction(
|
|||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
runtimeErrorOk: boolean = false
|
runtimeErrorOk: boolean = false
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
||||||
|
let sendRetries = 3;
|
||||||
|
for (;;) {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const signature = await connection.sendTransaction(from, transaction);
|
const signature = await connection.sendTransaction(from, transaction);
|
||||||
|
|
||||||
// Wait up to a couple seconds for a confirmation
|
// Wait up to a couple seconds for a confirmation
|
||||||
let i = 4;
|
let status = 'SignatureNotFound';
|
||||||
|
let statusRetries = 4;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const status = await connection.getSignatureStatus(signature);
|
status = await connection.getSignatureStatus(signature);
|
||||||
switch (status) {
|
if (status !== 'SignatureNotFound') {
|
||||||
case 'Confirmed':
|
|
||||||
return;
|
|
||||||
case 'ProgramRuntimeError':
|
|
||||||
if (runtimeErrorOk) return;
|
|
||||||
//fall through
|
|
||||||
case 'GenericError':
|
|
||||||
default:
|
|
||||||
throw new Error(`Transaction ${signature} failed (${status})`);
|
|
||||||
case 'SignatureNotFound':
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
if (--i < 0) {
|
if (--statusRetries <= 0) {
|
||||||
const duration = (Date.now() - start) / 1000;
|
const duration = (Date.now() - start) / 1000;
|
||||||
throw new Error(`Transaction '${signature}' was not confirmed in ${duration.toFixed(2)} seconds (${status})`);
|
throw new Error(`Transaction '${signature}' was not confirmed in ${duration.toFixed(2)} seconds (${status})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (status === 'Confirmed') ||
|
||||||
|
(status === 'ProgramRuntimeError' && runtimeErrorOk) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status !== 'AccountInUse' || --sendRetries <= 0) {
|
||||||
|
throw new Error(`Transaction ${signature} failed (${status})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user