Skip to content

Commit

Permalink
docs: handling UTXO error in transaction re-submissions (#3050)
Browse files Browse the repository at this point in the history
  • Loading branch information
Torres-ssf authored Aug 30, 2024
1 parent a36626a commit 2ffaaf7
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { bn, type FuelError } from 'fuels';
import { launchTestNode } from 'fuels/test-utils';

/**
* @group node
* @group browser
*/
describe('Resubmitting Failed Transactions', () => {
it('should submit transaction just fine', async () => {
const {
provider,
wallets: [wallet, recipient],
} = await launchTestNode({
walletsConfig: {
count: 2,
},
});
const baseAssetId = provider.getBaseAssetId();

const transferAmount = 1000;

// #region resubmitting-failed-transactions-1
const transactionRequest = await wallet.createTransfer(
recipient.address,
transferAmount,
baseAssetId
);

const response = await wallet.sendTransaction(transactionRequest);
// #endregion resubmitting-failed-transactions-1

// #region resubmitting-failed-transactions-2
const result = await response.waitForResult();
// #endregion resubmitting-failed-transactions-2

expect(result.isStatusSuccess).toBeTruthy();
});

it('should try to re-submit the transaction', async () => {
const {
provider,
wallets: [wallet, recipient],
} = await launchTestNode({
walletsConfig: {
count: 2,
},
});
const baseAssetId = provider.getBaseAssetId();
const transferAmount = 1000;

await expect(async () => {
// #region resubmitting-failed-transactions-3
const transactionRequest = await wallet.createTransfer(
recipient.address,
transferAmount,
baseAssetId
);

// Set the gasLimit to 0 to force revert with OutOfGas error
transactionRequest.gasLimit = bn(0);

// Transaction will be successfully submitted
const response = await wallet.sendTransaction(transactionRequest);
try {
await response.waitForResult();
} catch (error) {
if (/OutOfGas/.test((<FuelError>error).message)) {
transactionRequest.gasLimit = bn(1000);
// Re-submission will fail
await wallet.sendTransaction(transactionRequest);
}
}
// #endregion resubmitting-failed-transactions-3
}).rejects.toThrow('Transaction is not inserted. UTXO does not exist: 0x');

await expect(
(async () => {
const transactionRequest = await wallet.createTransfer(
recipient.address,
transferAmount,
baseAssetId
);

transactionRequest.gasLimit = bn(0);

const response = await wallet.sendTransaction(transactionRequest);
// #region resubmitting-failed-transactions-4
try {
await response.waitForResult();
} catch (error) {
if (/OutOfGas/.test((<FuelError>error).message)) {
const transactionRequest2 = await wallet.createTransfer(
recipient.address,
transferAmount,
baseAssetId
);

await wallet.sendTransaction(transactionRequest2);
}
}
// #endregion resubmitting-failed-transactions-4
})()
).resolves.not.toThrow();
});
});
4 changes: 4 additions & 0 deletions apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ export default defineConfig({
text: 'GraphQL Integration',
link: '/guide/cookbook/graphql-integration',
},
{
text: 'Resubmitting Failed Transactions',
link: '/guide/cookbook/resubmitting-failed-transactions',
},
],
},
{
Expand Down
38 changes: 38 additions & 0 deletions apps/docs/src/guide/cookbook/resubmitting-failed-transactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Resubmitting Failed Transactions

In certain scenarios, you might need to implement a solution to resubmit failed transactions to the Fuel Network. While this approach can be effective, there are important considerations to remember.


## Submission and Processing

When submitting a transaction, you will first get a response.

<<< @/../../docs-snippets/src/guide/cookbook/resubmitting-failed-transactions.test.ts#resubmitting-failed-transactions-1{ts:line-numbers}

If the `sendTransaction` method resolves without an error, we know that the transaction was successfully submitted and accepted by the network. However, this does not guarantee that the transaction has been processed; it only indicates that the transaction has been accepted and placed in a queue for processing.

To determine whether the transaction has been processed, you must call `waitForResult`, which will either resolve (with the processed transaction) or reject with an error.

<<< @/../../docs-snippets/src/guide/cookbook/resubmitting-failed-transactions.test.ts#resubmitting-failed-transactions-2{ts:line-numbers}

In other words:
- If `sendTransaction` is rejected with an error, the transaction was not accepted by the network and is not processed.
- If `waitForResult` is rejected with an error, the transaction was accepted but reverted during processing.

## Resources Spent When a Transaction Is Processed

If a transaction is reverted during processing, the Fuel VM will still consume the funded resources to cover the gas used up to the point of failure. After deducting the gas cost, the remaining funds will be added to a new UTXO (Unspent Transaction Output) addressed to the owner.

Attempting to resubmit the same transaction request that failed during processing will likely result in an error, as the initially spent resources no longer exist.

<<< @/../../docs-snippets/src/guide/cookbook/resubmitting-failed-transactions.test.ts#resubmitting-failed-transactions-3{ts:line-numbers}

The attempt from the above snippet will result in the error:

```console
FuelError: Transaction is not inserted. UTXO does not exist: {{utxoId}}
```

To safely retry a transaction that failed during processing, you should reassemble the request from scratch and resubmit it.

<<< @/../../docs-snippets/src/guide/cookbook/resubmitting-failed-transactions.test.ts#resubmitting-failed-transactions-4{ts:line-numbers}

0 comments on commit 2ffaaf7

Please sign in to comment.