Skip to content

Commit

Permalink
feat(wallet): the wallet now only fetches UTXOs on tx history change
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelCastilloB committed Nov 14, 2024
1 parent 9e9f634 commit ea4e5ed
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 15 deletions.
4 changes: 1 addition & 3 deletions packages/wallet/src/Wallets/BaseWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import {
createUtxoTracker,
createWalletUtil,
currentEpochTracker,
distinctBlock,
distinctEraSummaries
} from '../services';
import { AddressType, Bip32Account, GroupedAddress, WitnessedTx, Witnesser, util } from '@cardano-sdk/key-management';
Expand Down Expand Up @@ -397,7 +396,6 @@ export class BaseWallet implements ObservableWallet {
store: stores.tip,
syncStatus: this.syncStatus
});
const tipBlockHeight$ = distinctBlock(this.tip$);

this.txSubmitProvider = new SmartTxSubmitProvider(
{ retryBackoffConfig },
Expand Down Expand Up @@ -499,11 +497,11 @@ export class BaseWallet implements ObservableWallet {

this.utxo = createUtxoTracker({
addresses$,
history$: this.transactions.history$,
logger: contextLogger(this.#logger, 'utxo'),
onFatalError,
retryBackoffConfig,
stores,
tipBlockHeight$,
transactionsInFlight$: this.transactions.outgoing.inFlight$,
utxoProvider: this.utxoProvider
});
Expand Down
17 changes: 14 additions & 3 deletions packages/wallet/src/services/TransactionsTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export const createAddressTransactionsProvider = ({
);
const duplicateTransactions =
lastStoredTransaction && intersectionBy(localTransactions, newTransactions, (tx) => tx.id);

if (typeof duplicateTransactions !== 'undefined' && duplicateTransactions.length === 0) {
const rollbackTransactions = localTransactions.filter(
({ blockHeader: { blockNo } }) => blockNo >= lowerBound
Expand All @@ -172,8 +173,16 @@ export const createAddressTransactionsProvider = ({
// Rollback by 1 block, try again in next loop iteration
localTransactions = localTransactions.filter(({ blockHeader: { blockNo } }) => blockNo < lowerBound);
} else {
localTransactions = unionBy(localTransactions, newTransactions, (tx) => tx.id);
store.setAll(localTransactions);
const lastLocalTxs = localTransactions.slice(-newTransactions.length);
const areTransactionsSame =
lastLocalTxs.length === newTransactions.length &&
lastLocalTxs.every((tx, index) => tx.id === newTransactions[index].id);

if (!areTransactionsSame) {
localTransactions = unionBy(localTransactions, newTransactions, (tx) => tx.id);
store.setAll(localTransactions);
}

return localTransactions;
}
}
Expand Down Expand Up @@ -247,7 +256,9 @@ export const createTransactionsTracker = (

const transactionsSource$ = new TrackerSubject(txSource$);

const historicalTransactions$ = createHistoricalTransactionsTrackerSubject(transactionsSource$);
const historicalTransactions$ = createHistoricalTransactionsTrackerSubject(transactionsSource$).pipe(
tap((transactions) => logger.debug(`History transactions count: ${transactions?.length || 0}`))
);

const [onChainNewTxPhase2Failed$, onChainNewTxSuccess$] = partition(
newTransactions$(historicalTransactions$).pipe(share()),
Expand Down
13 changes: 7 additions & 6 deletions packages/wallet/src/services/UtxoTracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { RetryBackoffConfig } from 'backoff-rxjs';
import { TxInFlight, UtxoTracker } from './types';
import { WalletStores } from '../persistence';
import { coldObservableProvider } from '@cardano-sdk/util-rxjs';
import { sortUtxoByTxIn } from '@cardano-sdk/input-selection';
import chunk from 'lodash/chunk.js';
import uniqWith from 'lodash/uniqWith.js';

Expand All @@ -17,7 +18,7 @@ export interface UtxoTrackerProps {
addresses$: Observable<Cardano.PaymentAddress[]>;
stores: Pick<WalletStores, 'utxo' | 'unspendableUtxo'>;
transactionsInFlight$: Observable<TxInFlight[]>;
tipBlockHeight$: Observable<Cardano.BlockNo>;
history$: Observable<Cardano.HydratedTx[]>;
retryBackoffConfig: RetryBackoffConfig;
logger: Logger;
onFatalError?: (value: unknown) => void;
Expand All @@ -31,7 +32,7 @@ export interface UtxoTrackerInternals {
export const createUtxoProvider = (
utxoProvider: UtxoProvider,
addresses$: Observable<Cardano.PaymentAddress[]>,
tipBlockHeight$: Observable<Cardano.BlockNo>,
history$: Observable<Cardano.HydratedTx[]>,
retryBackoffConfig: RetryBackoffConfig,
onFatalError?: (value: unknown) => void
) =>
Expand All @@ -49,10 +50,10 @@ export const createUtxoProvider = (
utxos = [...utxos, ...(await utxoProvider.utxoByAddresses({ addresses }))];
}

return utxos;
return utxos.sort(sortUtxoByTxIn);
},
retryBackoffConfig,
trigger$: tipBlockHeight$
trigger$: history$
})
)
);
Expand All @@ -64,13 +65,13 @@ export const createUtxoTracker = (
stores,
transactionsInFlight$,
retryBackoffConfig,
tipBlockHeight$,
history$,
logger,
onFatalError
}: UtxoTrackerProps,
{
utxoSource$ = new PersistentCollectionTrackerSubject<Cardano.Utxo>(
() => createUtxoProvider(utxoProvider, addresses$, tipBlockHeight$, retryBackoffConfig, onFatalError),
() => createUtxoProvider(utxoProvider, addresses$, history$, retryBackoffConfig, onFatalError),
stores.utxo
),
unspendableUtxoSource$ = new PersistentCollectionTrackerSubject(
Expand Down
25 changes: 22 additions & 3 deletions packages/wallet/src/services/util/equals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,31 @@ export const tipEquals = (a: Cardano.Tip, b: Cardano.Tip) => a.hash === b.hash;

export const txEquals = (a: Cardano.HydratedTx, b: Cardano.HydratedTx) => a.id === b.id;

export const transactionsEquals = (a: Cardano.HydratedTx[], b: Cardano.HydratedTx[]) => sameArrayItems(a, b, txEquals);
export const sameSortedArrayItems = <T>(arrayA: T[], arrayB: T[], itemEquals: (a: T, b: T) => boolean): boolean => {
if (arrayA.length !== arrayB.length) return false;

for (const [i, element] of arrayA.entries()) {
if (!itemEquals(element, arrayB[i])) {
return false;
}
}

return true;
};

export const transactionsEquals = (a: Cardano.HydratedTx[], b: Cardano.HydratedTx[]) => {
if (a === b) return true;

return sameSortedArrayItems(a, b, txEquals);
};

export const txInEquals = (a: Cardano.TxIn, b: Cardano.TxIn) => a.txId === b.txId && a.index === b.index;

export const utxoEquals = (a: Cardano.Utxo[], b: Cardano.Utxo[]) =>
sameArrayItems(a, b, ([aTxIn], [bTxIn]) => txInEquals(aTxIn, bTxIn));
export const utxoEquals = (a: Cardano.Utxo[], b: Cardano.Utxo[]) => {
if (a === b) return true;

return sameSortedArrayItems(a, b, ([aTxIn], [bTxIn]) => txInEquals(aTxIn, bTxIn));
};

export const eraSummariesEquals = (a: EraSummary[], b: EraSummary[]) =>
sameArrayItems(a, b, (es1, es2) => es1.start.slot === es2.start.slot);
Expand Down

0 comments on commit ea4e5ed

Please sign in to comment.