From 6b3ec239f4c296bb5b9198f2ff6e682424ad50a0 Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Tue, 23 Jul 2024 12:16:34 -0300 Subject: [PATCH 1/9] add check --- .changeset/honest-fishes-mix.md | 5 +++++ packages/account/src/account.ts | 9 +++++++++ packages/errors/src/error-codes.ts | 1 + 3 files changed, 15 insertions(+) create mode 100644 .changeset/honest-fishes-mix.md diff --git a/.changeset/honest-fishes-mix.md b/.changeset/honest-fishes-mix.md new file mode 100644 index 00000000000..c66f76421bc --- /dev/null +++ b/.changeset/honest-fishes-mix.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/account": patch +--- + +chore: handle exceeding maximum inputs when funding a transaction \ No newline at end of file diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index f83f75fc491..cf0c0dba9e8 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -63,6 +63,8 @@ export type EstimatedTxParams = Pick< >; const MAX_FUNDING_ATTEMPTS = 2; +const MAX_TRANSACTION_INPUTS = 255; + export type FakeResources = Partial & Required>; /** @@ -201,6 +203,13 @@ export class Account extends AbstractAccount { async fund(request: T, params: EstimatedTxParams): Promise { const { addedSignatures, estimatedPredicates, requiredQuantities, updateMaxFee } = params; + if (request.inputs.length > MAX_TRANSACTION_INPUTS) { + throw new FuelError( + ErrorCode.EXCEEDING_MAX_INPUTS_WHEN_FUNDING, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ); + } + const fee = request.maxFee; const baseAssetId = this.provider.getBaseAssetId(); const requiredInBaseAsset = diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index 4fc0c2f59d7..752e4432947 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -73,6 +73,7 @@ export enum ErrorCode { DUPLICATED_POLICY = 'duplicated-policy', TRANSACTION_SQUEEZED_OUT = 'transaction-squeezed-out', CONTRACT_SIZE_EXCEEDS_LIMIT = 'contract-size-exceeds-limit', + EXCEEDING_MAX_INPUTS_WHEN_FUNDING = 'exceeding-max-inputs-when-funding', // receipt INVALID_RECEIPT_TYPE = 'invalid-receipt-type', From 9535163ccfc0677c019ede3d65536df9c54639a9 Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Tue, 23 Jul 2024 14:44:30 -0300 Subject: [PATCH 2/9] refactoring --- packages/account/src/account.ts | 12 ++++++++---- packages/errors/src/error-codes.ts | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index cf0c0dba9e8..6a8a9e28227 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -63,8 +63,6 @@ export type EstimatedTxParams = Pick< >; const MAX_FUNDING_ATTEMPTS = 2; -const MAX_TRANSACTION_INPUTS = 255; - export type FakeResources = Partial & Required>; /** @@ -203,9 +201,15 @@ export class Account extends AbstractAccount { async fund(request: T, params: EstimatedTxParams): Promise { const { addedSignatures, estimatedPredicates, requiredQuantities, updateMaxFee } = params; - if (request.inputs.length > MAX_TRANSACTION_INPUTS) { + const { + consensusParameters: { + txParameters: { maxInputs }, + }, + } = this.provider.getChain(); + + if (bn(request.inputs.length) > maxInputs) { throw new FuelError( - ErrorCode.EXCEEDING_MAX_INPUTS_WHEN_FUNDING, + ErrorCode.MAX_INPUTS_EXCEEDED, 'The transaction exceeds the maximum allowed number of inputs for funding.' ); } diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index 752e4432947..2c1666d922f 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -73,7 +73,7 @@ export enum ErrorCode { DUPLICATED_POLICY = 'duplicated-policy', TRANSACTION_SQUEEZED_OUT = 'transaction-squeezed-out', CONTRACT_SIZE_EXCEEDS_LIMIT = 'contract-size-exceeds-limit', - EXCEEDING_MAX_INPUTS_WHEN_FUNDING = 'exceeding-max-inputs-when-funding', + MAX_INPUTS_EXCEEDED = 'max-inputs-exceeded', // receipt INVALID_RECEIPT_TYPE = 'invalid-receipt-type', From 786501a9a2b585686cded75f179398207df2c20b Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Thu, 25 Jul 2024 09:19:35 -0300 Subject: [PATCH 3/9] move if --- packages/account/src/account.test.ts | 2 ++ packages/account/src/account.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 7e64ce8501b..1beb241de87 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -221,6 +221,8 @@ describe('Account', () => { expect(addResourcesSpy).toHaveBeenCalledWith(resourcesToSpend); }); + it('should throws if max of inputs was exceeded', async () => {}); + it('should execute sendTransaction just fine', async () => { const transactionRequestLike: providersMod.TransactionRequestLike = { type: providersMod.TransactionType.Script, diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index 80759455b57..a10c49f93ab 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -207,13 +207,6 @@ export class Account extends AbstractAccount { }, } = this.provider.getChain(); - if (bn(request.inputs.length) > maxInputs) { - throw new FuelError( - ErrorCode.MAX_INPUTS_EXCEEDED, - 'The transaction exceeds the maximum allowed number of inputs for funding.' - ); - } - const fee = request.maxFee; const baseAssetId = this.provider.getBaseAssetId(); const requiredInBaseAsset = @@ -299,6 +292,13 @@ export class Account extends AbstractAccount { fundingAttempts += 1; } + if (bn(request.inputs.length).gt(maxInputs)) { + throw new FuelError( + ErrorCode.MAX_INPUTS_EXCEEDED, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ); + } + request.updatePredicateGasUsed(estimatedPredicates); const requestToReestimate = clone(request); From 6e2337d832a79698a8340c3d3733e387af77e0fe Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Mon, 29 Jul 2024 10:07:54 -0300 Subject: [PATCH 4/9] allocate method in other place --- packages/account/src/account.ts | 13 ------------- packages/account/src/providers/provider.ts | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/account/src/account.ts b/packages/account/src/account.ts index a10c49f93ab..af198d012fa 100644 --- a/packages/account/src/account.ts +++ b/packages/account/src/account.ts @@ -201,12 +201,6 @@ export class Account extends AbstractAccount { async fund(request: T, params: EstimatedTxParams): Promise { const { addedSignatures, estimatedPredicates, requiredQuantities, updateMaxFee } = params; - const { - consensusParameters: { - txParameters: { maxInputs }, - }, - } = this.provider.getChain(); - const fee = request.maxFee; const baseAssetId = this.provider.getBaseAssetId(); const requiredInBaseAsset = @@ -292,13 +286,6 @@ export class Account extends AbstractAccount { fundingAttempts += 1; } - if (bn(request.inputs.length).gt(maxInputs)) { - throw new FuelError( - ErrorCode.MAX_INPUTS_EXCEEDED, - 'The transaction exceeds the maximum allowed number of inputs for funding.' - ); - } - request.updatePredicateGasUsed(estimatedPredicates); const requestToReestimate = clone(request); diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index ba256df8002..52402b62c53 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -685,6 +685,15 @@ Supported fuel-core version: ${supportedVersion}.` }); } + #validateTransaction(tx: TransactionRequest, consensusParameters: ConsensusParameters) { + if (bn(tx.inputs.length).gt(consensusParameters.txParameters.maxInputs)) { + throw new FuelError( + ErrorCode.MAX_INPUTS_EXCEEDED, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ); + } + } + /** * Submits a transaction to the chain to be executed. * @@ -707,6 +716,10 @@ Supported fuel-core version: ${supportedVersion}.` } // #endregion Provider-sendTransaction + const { consensusParameters } = this.getChain(); + + this.#validateTransaction(transactionRequest, consensusParameters); + const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); let abis: JsonAbisFromAllCalls | undefined; From 1da6e45e911c294b14ad98149b071c6b49947f12 Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Thu, 1 Aug 2024 11:26:28 -0300 Subject: [PATCH 5/9] add test --- packages/account/src/account.test.ts | 2 - .../account/src/providers/provider.test.ts | 58 ++++++++++++++++++- packages/account/src/providers/provider.ts | 6 +- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/packages/account/src/account.test.ts b/packages/account/src/account.test.ts index 1beb241de87..7e64ce8501b 100644 --- a/packages/account/src/account.test.ts +++ b/packages/account/src/account.test.ts @@ -221,8 +221,6 @@ describe('Account', () => { expect(addResourcesSpy).toHaveBeenCalledWith(resourcesToSpend); }); - it('should throws if max of inputs was exceeded', async () => {}); - it('should execute sendTransaction just fine', async () => { const transactionRequestLike: providersMod.TransactionRequestLike = { type: providersMod.TransactionType.Script, diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 167a58308e9..9242e7cd006 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -8,7 +8,7 @@ import { BN, bn } from '@fuel-ts/math'; import type { Receipt } from '@fuel-ts/transactions'; import { InputType, ReceiptType, TransactionType } from '@fuel-ts/transactions'; import { DateTime, arrayify, sleep } from '@fuel-ts/utils'; -import { ASSET_A } from '@fuel-ts/utils/test-utils'; +import { ASSET_A, ASSET_B } from '@fuel-ts/utils/test-utils'; import { versions } from '@fuel-ts/versions'; import * as fuelTsVersionsMod from '@fuel-ts/versions'; @@ -26,6 +26,7 @@ import { import { Wallet } from '../wallet'; import type { Coin } from './coin'; +import { coinQuantityfy } from './coin-quantity'; import type { ChainInfo, CursorPaginationArgs, NodeInfo } from './provider'; import Provider, { BLOCKS_PAGE_SIZE_LIMIT, @@ -33,7 +34,7 @@ import Provider, { RESOURCES_PAGE_SIZE_LIMIT, } from './provider'; import type { CoinTransactionRequestInput } from './transaction-request'; -import { ScriptTransactionRequest, CreateTransactionRequest } from './transaction-request'; +import { CreateTransactionRequest, ScriptTransactionRequest } from './transaction-request'; import { TransactionResponse } from './transaction-response'; import type { SubmittedStatus } from './transaction-summary/types'; import * as gasMod from './utils/gas'; @@ -541,6 +542,59 @@ describe('Provider', () => { }); }); + it.only('should throws if max of inputs was exceeded', async () => { + const maxInputs = 2; + using launched = await setupTestProviderAndWallets({ + nodeOptions: { + snapshotConfig: { + chainConfig: { + consensus_parameters: { + V1: { + tx_params: { + V1: { + max_inputs: maxInputs, + }, + }, + }, + }, + }, + }, + }, + walletsConfig: { + amountPerCoin: 500_000, + }, + }); + + const { + wallets: [sender, receiver], + provider, + } = launched; + + const request = new ScriptTransactionRequest(); + + const quantities = [coinQuantityfy([1000, ASSET_A]), coinQuantityfy([500, ASSET_B])]; + const resources = await sender.getResourcesToSpend(quantities); + + request.addCoinOutput(receiver.address, 500, provider.getBaseAssetId()); + + const txCost = await sender.getTransactionCost(request); + + request.gasLimit = txCost.gasUsed; + request.maxFee = txCost.maxFee; + + request.addResources(resources); + + await sender.fund(request, txCost); + + await expectToThrowFuelError( + () => sender.sendTransaction(request), + new FuelError( + ErrorCode.MAX_INPUTS_EXCEEDED, + 'The transaction exceeds the maximum allowed number of inputs for funding.' + ) + ); + }); + it('can getBlocks', async () => { using launched = await setupTestProviderAndWallets(); const blocksLenght = 5; diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 18b69dd98f3..1188eeebc46 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -695,7 +695,7 @@ Supported fuel-core version: ${supportedVersion}.` }); } - #validateTransaction(tx: TransactionRequest, consensusParameters: ConsensusParameters) { + private validateTransaction(tx: TransactionRequest, consensusParameters: ConsensusParameters) { if (bn(tx.inputs.length).gt(consensusParameters.txParameters.maxInputs)) { throw new FuelError( ErrorCode.MAX_INPUTS_EXCEEDED, @@ -727,7 +727,9 @@ Supported fuel-core version: ${supportedVersion}.` const { consensusParameters } = this.getChain(); - this.#validateTransaction(transactionRequest, consensusParameters); + this.validateTransaction(transactionRequest, consensusParameters); + + console.log('teste'); const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); From aad51c89ead3c10980a8a1521973442a8b0015ef Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Thu, 1 Aug 2024 11:27:41 -0300 Subject: [PATCH 6/9] remove .only --- packages/account/src/providers/provider.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/account/src/providers/provider.test.ts b/packages/account/src/providers/provider.test.ts index 9242e7cd006..83830bdc0a6 100644 --- a/packages/account/src/providers/provider.test.ts +++ b/packages/account/src/providers/provider.test.ts @@ -542,7 +542,7 @@ describe('Provider', () => { }); }); - it.only('should throws if max of inputs was exceeded', async () => { + it('should throws if max of inputs was exceeded', async () => { const maxInputs = 2; using launched = await setupTestProviderAndWallets({ nodeOptions: { From 6f425c2180d9208aa0d8434878fc2f8c0cb228ba Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Thu, 1 Aug 2024 11:56:55 -0300 Subject: [PATCH 7/9] remove console.log --- packages/account/src/providers/provider.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/account/src/providers/provider.ts b/packages/account/src/providers/provider.ts index 1188eeebc46..e6f155be09d 100644 --- a/packages/account/src/providers/provider.ts +++ b/packages/account/src/providers/provider.ts @@ -729,8 +729,6 @@ Supported fuel-core version: ${supportedVersion}.` this.validateTransaction(transactionRequest, consensusParameters); - console.log('teste'); - const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); let abis: JsonAbisFromAllCalls | undefined; From 8cbcc6d4b77dcee96d377db20a33e7ddecb0ef34 Mon Sep 17 00:00:00 2001 From: Miguel Oliveira Date: Mon, 5 Aug 2024 13:07:19 -0300 Subject: [PATCH 8/9] add error docs --- apps/docs/src/guide/errors/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/docs/src/guide/errors/index.md b/apps/docs/src/guide/errors/index.md index af55d41ce4f..fe61222a90a 100644 --- a/apps/docs/src/guide/errors/index.md +++ b/apps/docs/src/guide/errors/index.md @@ -298,3 +298,7 @@ The purpose of the lock function is to provide a way to ensure that the implemen In cases where the error hasn't been mapped yet, this code will be used. If you believe you found a bug, please report the [issue](https://github.com/FuelLabs/fuels-ts/issues/new/choose) to the team. + +### `MAX_INPUTS_EXCEEDED` + +When the number of transaction inputs exceeds the maximum limit allowed by the blockchain. \ No newline at end of file From 2180ac984cd31ae83a9799a96836e6559cdae2cb Mon Sep 17 00:00:00 2001 From: Miguel Tavares Date: Tue, 6 Aug 2024 11:21:02 -0300 Subject: [PATCH 9/9] Update .changeset/honest-fishes-mix.md Co-authored-by: Peter Smith --- .changeset/honest-fishes-mix.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/honest-fishes-mix.md b/.changeset/honest-fishes-mix.md index c66f76421bc..f381e3e9939 100644 --- a/.changeset/honest-fishes-mix.md +++ b/.changeset/honest-fishes-mix.md @@ -1,5 +1,6 @@ --- "@fuel-ts/account": patch +"@fuel-ts/errors": patch --- chore: handle exceeding maximum inputs when funding a transaction \ No newline at end of file