Skip to content

Commit

Permalink
fixup! fixup! feat(wallet): the wallet now only fetches UTXOs on tx h…
Browse files Browse the repository at this point in the history
…istory change
  • Loading branch information
mirceahasegan committed Nov 14, 2024
1 parent 6d0e216 commit d243142
Showing 1 changed file with 83 additions and 67 deletions.
150 changes: 83 additions & 67 deletions packages/wallet/src/services/TransactionsTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,15 +105,84 @@ const allTransactionsByAddresses = async (
return response;
};

export const createAddressTransactionsProvider = ({
const findIntersectionAndUpdateTxStore = ({
chainHistoryProvider,
addresses$,
logger,
store,
retryBackoffConfig,
onFatalError,
tipBlockHeight$,
store,
logger,
onFatalError
}: TransactionsTrackerInternalsProps): TransactionsTrackerInternals => {
rollback$,
localTransactions,
addresses
}: Pick<
TransactionsTrackerInternalsProps,
'chainHistoryProvider' | 'logger' | 'store' | 'retryBackoffConfig' | 'onFatalError' | 'tipBlockHeight$'
> & {
localTransactions: Cardano.HydratedTx[];
rollback$: Subject<Cardano.HydratedTx>;
addresses: Cardano.PaymentAddress[];
}) =>
coldObservableProvider({
// Do not re-fetch transactions twice on load when tipBlockHeight$ loads from storage first
// It should also help when using poor internet connection.
// Caveat is that local transactions might get out of date...
combinator: exhaustMap,
equals: transactionsEquals,
onFatalError,
provider: async () => {
let rollbackOccured = false;
// eslint-disable-next-line no-constant-condition
while (true) {
const lastStoredTransaction: Cardano.HydratedTx | undefined = localTransactions[localTransactions.length - 1];

lastStoredTransaction &&
logger.debug(
`Last stored tx: ${lastStoredTransaction?.id} block:${lastStoredTransaction?.blockHeader.blockNo}`
);

const lowerBound = lastStoredTransaction?.blockHeader.blockNo;
const newTransactions = await allTransactionsByAddresses(chainHistoryProvider, {
addresses,
blockRange: { lowerBound }
});

logger.debug(
`chainHistoryProvider returned ${newTransactions.length} transactions`,
lowerBound !== undefined && `since block ${lowerBound}`
);

const txRolledBack = lastStoredTransaction && newTransactions[0]?.id !== lastStoredTransaction.id;
if (txRolledBack) {
rollbackOccured = true;
logger.debug(`Transaction ${lastStoredTransaction.id} was rolled back`);
rollback$.next(lastStoredTransaction);

// Rollback by 1 block, try again in next loop iteration
localTransactions.pop();
} else {
if (lastStoredTransaction) {
// lastStoredTransaction is also the first in newTransactions
newTransactions.shift();
}

if (newTransactions.length > 0 || rollbackOccured) {
localTransactions = [...localTransactions, ...newTransactions];
store.setAll(localTransactions);
}

return localTransactions;
}
}
},
retryBackoffConfig,
trigger$: tipBlockHeight$
});

export const createAddressTransactionsProvider = (
props: TransactionsTrackerInternalsProps
): TransactionsTrackerInternals => {
const { addresses$, store, logger } = props;
const rollback$ = new Subject<Cardano.HydratedTx>();
const storedTransactions$ = store.getAll().pipe(share());
return {
Expand All @@ -125,67 +194,14 @@ export const createAddressTransactionsProvider = ({
)
),
combineLatest([addresses$, storedTransactions$.pipe(defaultIfEmpty([] as Cardano.HydratedTx[]))]).pipe(
// eslint-disable-next-line sonarjs/cognitive-complexity
switchMap(([addresses, storedTransactions]) => {
let localTransactions: Cardano.HydratedTx[] = [...storedTransactions];

return coldObservableProvider({
// Do not re-fetch transactions twice on load when tipBlockHeight$ loads from storage first
// It should also help when using poor internet connection.
// Caveat is that local transactions might get out of date...
combinator: exhaustMap,
equals: transactionsEquals,
onFatalError,
provider: async () => {
let rollbackOccured = false;
// eslint-disable-next-line no-constant-condition
while (true) {
const lastStoredTransaction: Cardano.HydratedTx | undefined =
localTransactions[localTransactions.length - 1];

lastStoredTransaction &&
logger.debug(
`Last stored tx: ${lastStoredTransaction?.id} block:${lastStoredTransaction?.blockHeader.blockNo}`
);

const lowerBound = lastStoredTransaction?.blockHeader.blockNo;
const newTransactions = await allTransactionsByAddresses(chainHistoryProvider, {
addresses,
blockRange: { lowerBound }
});

logger.debug(
`chainHistoryProvider returned ${newTransactions.length} transactions`,
lowerBound !== undefined && `since block ${lowerBound}`
);

const txRolledBack = lastStoredTransaction && newTransactions[0]?.id !== lastStoredTransaction.id;
if (txRolledBack) {
rollbackOccured = true;
logger.debug(`Transaction ${lastStoredTransaction.id} was rolled back`);
rollback$.next(lastStoredTransaction);

// Rollback by 1 block, try again in next loop iteration
localTransactions.pop();
} else {
if (lastStoredTransaction) {
// lastStoredTransaction is also the first in newTransactions
newTransactions.shift();
}

if (newTransactions.length > 0 || rollbackOccured) {
localTransactions = [...localTransactions, ...newTransactions];
store.setAll(localTransactions);
}

return localTransactions;
}
}
},
retryBackoffConfig,
trigger$: tipBlockHeight$
});
})
switchMap(([addresses, storedTransactions]) =>
findIntersectionAndUpdateTxStore({
addresses,
localTransactions: [...storedTransactions],
rollback$,
...props
})
)
)
)
};
Expand Down

0 comments on commit d243142

Please sign in to comment.