fix: txnNotFound error (#1883)

* add validation for `txnNotFound` error

* update version to `2.1.1`
This commit is contained in:
Mukul Jangid
2021-12-23 20:34:35 -05:00
committed by GitHub
parent 5d556c6afe
commit 07f36e127f
4 changed files with 60 additions and 24 deletions

2
package-lock.json generated
View File

@@ -16659,7 +16659,7 @@
} }
}, },
"packages/xrpl": { "packages/xrpl": {
"version": "2.1.0", "version": "2.1.1",
"integrity": "sha512-NmrSYpXym7NzGABeXU1H8g4ZtCxRhr/3wu0lguxzcIYpcKPgWLYimg+s9NLLNbPWTZdxXu9SeSWu5zh4gyqAeA==", "integrity": "sha512-NmrSYpXym7NzGABeXU1H8g4ZtCxRhr/3wu0lguxzcIYpcKPgWLYimg+s9NLLNbPWTZdxXu9SeSWu5zh4gyqAeA==",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {

View File

@@ -2,7 +2,13 @@
Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release. Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xrpl-announce) for release announcements. We recommend that xrpl.js (ripple-lib) users stay up-to-date with the latest stable release.
## Unreleased ## Unreleased
## 2.1.1 (2021-12-23)
### Fixed
* A bug in submitAndWait function where the transaction could still be in queue and the server returns `txnNotFound`.
## 2.1.0 (2021-12-17)
### Added ### Added
* Support for the [XLS-20 NFT proposal](https://github.com/XRPLF/XRPL-Standards/discussions/46) * Support for the [XLS-20 NFT proposal](https://github.com/XRPLF/XRPL-Standards/discussions/46)

View File

@@ -1,6 +1,6 @@
{ {
"name": "xrpl", "name": "xrpl",
"version": "2.1.0", "version": "2.1.1",
"license": "ISC", "license": "ISC",
"description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser", "description": "A TypeScript/JavaScript API for interacting with the XRP Ledger in Node.js and the browser",
"files": [ "files": [

View File

@@ -74,16 +74,22 @@ async function submitAndWait(
): Promise<TxResponse> { ): Promise<TxResponse> {
const signedTx = await getSignedTx(this, transaction, opts) const signedTx = await getSignedTx(this, transaction, opts)
if (!hasLastLedgerSequence(signedTx)) { const lastLedger = getLastLedgerSequence(signedTx)
if (lastLedger == null) {
throw new ValidationError( throw new ValidationError(
'Transaction must contain a LastLedgerSequence value for reliable submission.', 'Transaction must contain a LastLedgerSequence value for reliable submission.',
) )
} }
await submitRequest(this, signedTx, opts?.failHard) const response = await submitRequest(this, signedTx, opts?.failHard)
const txHash = hashes.hashSignedTx(signedTx) const txHash = hashes.hashSignedTx(signedTx)
return waitForFinalTransactionOutcome(this, txHash) return waitForFinalTransactionOutcome(
this,
txHash,
lastLedger,
response.result.engine_result,
)
} }
// Helper functions // Helper functions
@@ -116,32 +122,53 @@ async function submitRequest(
* validated ledger, or the transaction's lastLedgerSequence has been surpassed by the * validated ledger, or the transaction's lastLedgerSequence has been surpassed by the
* latest ledger sequence (meaning it will never be included in a validated ledger). * latest ledger sequence (meaning it will never be included in a validated ledger).
*/ */
// eslint-disable-next-line max-params, max-lines-per-function -- this function needs to display and do with more information.
async function waitForFinalTransactionOutcome( async function waitForFinalTransactionOutcome(
client: Client, client: Client,
txHash: string, txHash: string,
lastLedger: number,
submissionResult: string,
): Promise<TxResponse> { ): Promise<TxResponse> {
await sleep(LEDGER_CLOSE_TIME) await sleep(LEDGER_CLOSE_TIME)
const txResponse = await client.request({ const latestLedger = await client.getLedgerIndex()
command: 'tx',
transaction: txHash, if (lastLedger < latestLedger) {
}) throw new XrplError(
`The latest ledger sequence ${latestLedger} is greater than the transaction's LastLedgerSequence (${lastLedger}).\n` +
`Preliminary result: ${submissionResult}`,
)
}
const txResponse = await client
.request({
command: 'tx',
transaction: txHash,
})
.catch(async (error) => {
// error is of an unknown type and hence we assert type to extract the value we need.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-member-access -- ^
const message = error.data.error as string
if (message === 'txnNotFound') {
return waitForFinalTransactionOutcome(
client,
txHash,
lastLedger,
submissionResult,
)
}
throw new Error(`${message} \n Preliminary result: ${submissionResult}.`)
})
if (txResponse.result.validated) { if (txResponse.result.validated) {
return txResponse return txResponse
} }
const txLastLedger = txResponse.result.LastLedgerSequence return waitForFinalTransactionOutcome(
if (txLastLedger == null) { client,
throw new XrplError('LastLedgerSequence cannot be null') txHash,
} lastLedger,
const latestLedger = await client.getLedgerIndex() submissionResult,
if (txLastLedger > latestLedger) {
return waitForFinalTransactionOutcome(client, txHash)
}
throw new XrplError(
`The latest ledger sequence ${latestLedger} is greater than the transaction's LastLedgerSequence (${txLastLedger}).`,
) )
} }
@@ -194,9 +221,12 @@ async function getSignedTx(
} }
// checks if there is a LastLedgerSequence as a part of the transaction // checks if there is a LastLedgerSequence as a part of the transaction
function hasLastLedgerSequence(transaction: Transaction | string): boolean { function getLastLedgerSequence(
transaction: Transaction | string,
): number | null {
const tx = typeof transaction === 'string' ? decode(transaction) : transaction const tx = typeof transaction === 'string' ? decode(transaction) : transaction
return typeof tx !== 'string' && tx.LastLedgerSequence != null // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- converts LastLedgSeq to number if present.
return tx.LastLedgerSequence as number | null
} }
// checks if the transaction is an AccountDelete transaction // checks if the transaction is an AccountDelete transaction