From 6244a8e4e8fb77d246f3c3d9e7056f6f342f751e Mon Sep 17 00:00:00 2001 From: Angel Castillo Date: Fri, 15 Nov 2024 12:39:46 +0800 Subject: [PATCH] fixup! feat(wallet): the wallet now only fetches UTXOs on tx history change --- .../src/services/TransactionsTracker.ts | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/packages/wallet/src/services/TransactionsTracker.ts b/packages/wallet/src/services/TransactionsTracker.ts index a4efd89e2a0..26f7fbd8c47 100644 --- a/packages/wallet/src/services/TransactionsTracker.ts +++ b/packages/wallet/src/services/TransactionsTracker.ts @@ -123,6 +123,30 @@ const getLastTransactionsAtBlock = ( return txsFromSameBlock; }; +export const revertLastBlock = ( + localTransactions: Cardano.HydratedTx[], + blockNo: Cardano.BlockNo, + rollback$: Subject, + logger: Logger +) => { + const result = [...localTransactions]; + + while (result.length > 0) { + const lastKnownTx = result[result.length - 1]; + + if (lastKnownTx.blockHeader.blockNo === blockNo) { + logger.debug(`Transaction ${lastKnownTx.id} was rolled back`); + + rollback$.next(lastKnownTx); + result.pop(); + } else { + break; + } + } + + return result; +}; + const findIntersectionAndUpdateTxStore = ({ chainHistoryProvider, logger, @@ -148,12 +172,9 @@ const findIntersectionAndUpdateTxStore = ({ combinator: exhaustMap, equals: transactionsEquals, onFatalError, - // eslint-disable-next-line complexity provider: async () => { // eslint-disable-next-line no-constant-condition while (true) { - let rollbackOccured = false; - const lastStoredTransaction: Cardano.HydratedTx | undefined = localTransactions[localTransactions.length - 1]; lastStoredTransaction && @@ -172,65 +193,46 @@ const findIntersectionAndUpdateTxStore = ({ lowerBound !== undefined && `since block ${lowerBound}` ); + // Fetching transactions from scratch, nothing else to do here. if (lowerBound === undefined) { - localTransactions = newTransactions; - return localTransactions; + return newTransactions; } + // If no transactions found from that block range, it means the last known block has been rolled back. if (newTransactions.length === 0) { - // If no transactions found from that block range, it means the last known block has been rolled back. - while (localTransactions.length > 0) { - const lastKnownTx = localTransactions[localTransactions.length - 1]; - - if (lastKnownTx.blockHeader.blockNo === lowerBound) { - rollbackOccured = true; - logger.debug(`Transaction ${lastKnownTx.id} was rolled back`); - rollback$.next(lastKnownTx); - localTransactions.pop(); - } else { - break; - } - } - + localTransactions = revertLastBlock(localTransactions, lowerBound, rollback$, logger); continue; } const localTxsFromSameBlock = getLastTransactionsAtBlock(localTransactions, lowerBound); + const firstSegmentOfNewTransactions = newTransactions.slice(0, localTxsFromSameBlock.length); - // Roll back transactions from this block not found in the result - for (const localTx of localTxsFromSameBlock) { - const txFound = newTransactions.find((tx) => tx.id === localTx.id); - - if (!txFound) { - rollbackOccured = true; - logger.debug(`Transaction ${localTx.id} was rolled back`); - rollback$.next(localTx); + // The first segment of new transaction should match exactly (same txs and same order) our last know TXs. Otherwise + // roll them back and re-apply in new order. + const sameLength = localTxsFromSameBlock.length === firstSegmentOfNewTransactions.length; + const sameOrder = + sameLength && localTxsFromSameBlock.every((tx, index) => tx.id === firstSegmentOfNewTransactions[index].id); - const index = localTransactions.findLastIndex((tx) => tx.id === localTx.id); + if (!sameLength || !sameOrder) { + localTransactions = revertLastBlock(localTransactions, lowerBound, rollback$, logger); + localTransactions = [...localTransactions, ...newTransactions]; + store.setAll(localTransactions); - if (index !== -1) { - localTransactions.splice(index, 1); - } - } + continue; } - if (!rollbackOccured) { - const lastLocalTxs = localTransactions.slice(-newTransactions.length); - - const areTransactionsSame = - lastLocalTxs.length === newTransactions.length && - lastLocalTxs.every((tx, index) => tx.id === newTransactions[index].id); + // No rollbacks, if they overlap 100% do nothing, otherwise add the difference. + const areTransactionsSame = + newTransactions.length === localTxsFromSameBlock.length && + localTxsFromSameBlock.every((tx, index) => tx.id === newTransactions[index].id); - if (!areTransactionsSame) { - // Remove overlapping transactions - localTransactions = localTransactions.slice(0, -localTxsFromSameBlock.length); - localTransactions = [...localTransactions, ...newTransactions]; - - store.setAll(localTransactions); - } - - return localTransactions; + if (!areTransactionsSame) { + // Skip overlapping transactions to avoid duplicates + localTransactions = [...localTransactions, ...newTransactions.slice(localTxsFromSameBlock.length)]; + store.setAll(localTransactions); } + + return localTransactions; } }, retryBackoffConfig,