Skip to content

Commit aa03442

Browse files
fixup! feat: asset tracker now uses local cache before fetching asset metadata
1 parent 84f3878 commit aa03442

File tree

4 files changed

+114
-26
lines changed

4 files changed

+114
-26
lines changed

packages/e2e/test/wallet_epoch_0/PersonalWallet/pouchDbWalletStores.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,26 @@ describe('PersonalWallet/pouchDbWalletStores', () => {
1717
it('stores and restores BaseWallet, continues sync after initial load', async () => {
1818
const wallet1 = (await getWallet({ env, logger, name: 'Test Wallet', stores: stores1 })).wallet;
1919

20+
// eslint-disable-next-line no-console
21+
console.error('XXXXXXXXXX a');
2022
// wallet1 fetched all responses from wallet provider
2123
await walletReady(wallet1);
22-
24+
// eslint-disable-next-line no-console
25+
console.error('XXXXXXXXXX b');
2326
// give it a second to store data to PouchDb, this is technically a race condition
2427
await delay(1000);
28+
// eslint-disable-next-line no-console
29+
console.error('XXXXXXXXXX c');
2530
// loading reward accounts involves loading many other pieces (transactions, stake pools etc.)
2631
const wallet1RewardAccounts = await firstValueFrom(wallet1.delegation.rewardAccounts$);
32+
// eslint-disable-next-line no-console
33+
console.error('XXXXXXXXXX d');
2734
const wallet1RewardsHistory = await firstValueFrom(wallet1.delegation.rewardsHistory$);
35+
// eslint-disable-next-line no-console
36+
console.error('XXXXXXXXXX e');
2837
wallet1.shutdown();
38+
// eslint-disable-next-line no-console
39+
console.error('XXXXXXXXXX f');
2940
// create a new wallet, with new stores sharing the underlying database
3041
const wallet2 = (
3142
await getWallet({
@@ -35,17 +46,36 @@ describe('PersonalWallet/pouchDbWalletStores', () => {
3546
stores: storage.createPouchDbWalletStores(walletName, { logger })
3647
})
3748
).wallet;
49+
50+
// eslint-disable-next-line no-console
51+
console.error('XXXXXXXXXX g');
3852
const tip = await firstValueFrom(wallet2.tip$);
53+
// eslint-disable-next-line no-console
54+
console.error('XXXXXXXXXX h');
3955
expect(await firstValueFrom(wallet2.delegation.rewardsHistory$)).toEqual(wallet1RewardsHistory);
56+
// eslint-disable-next-line no-console
57+
console.error('XXXXXXXXXX i');
4058
expect(await firstValueFrom(wallet1.delegation.rewardAccounts$)).toEqual(wallet1RewardAccounts);
59+
// eslint-disable-next-line no-console
60+
console.error('XXXXXXXXXX j');
4161
// if it's still syncing and reward accounts matched wallet1, it means it has loaded from storage.
4262
// technically a race condition too...
63+
// eslint-disable-next-line no-console
64+
console.error('XXXXXXXXXX k');
4365
expect(await firstValueFrom(wallet2.syncStatus.isSettled$)).toBe(false);
66+
// eslint-disable-next-line no-console
67+
console.error('XXXXXXXXXX l');
4468
// will time out if it's not syncing after load.
4569
await waitForWalletStateSettle(wallet2);
70+
// eslint-disable-next-line no-console
71+
console.error('XXXXXXXXXX n');
4672
// assert that it's updating wallet properties after fetching new data from the provider (at least the tip)
4773
await firstValueFrom(wallet2.tip$.pipe(filter((newTip) => newTip.slot !== tip.slot)));
74+
// eslint-disable-next-line no-console
75+
console.error('XXXXXXXXXX nxx');
4876
wallet2.shutdown();
77+
// eslint-disable-next-line no-console
78+
console.error('XXXXXXXXXX xxx');
4979
});
5080

5181
afterAll(() => firstValueFrom(stores1.destroy()));

packages/util-rxjs/src/coldObservableProvider.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,24 @@ export const coldObservableProvider = <T>({
5151
: // emit value, but also throw error to force retryBackoff to kick in
5252
concat(
5353
of(v),
54-
throwError(() => new Error('polling'))
54+
defer(() => {
55+
// Add logging here
56+
// eslint-disable-next-line no-console
57+
console.error('Poll until condition not met. Value:', v);
58+
// eslint-disable-next-line no-console
59+
console.error('Emitting error to trigger retry.');
60+
return throwError(() => new Error('polling'));
61+
})
5562
)
5663
)
5764
)
5865
).pipe(
5966
retryBackoff({
6067
...retryBackoffConfig,
6168
shouldRetry: (error) => {
69+
// eslint-disable-next-line no-console
70+
console.error('Retrying due to error:', error.message);
71+
6272
if (retryBackoffConfig.shouldRetry && !retryBackoffConfig.shouldRetry(error)) return false;
6373

6474
if (error instanceof InvalidStringError) {

packages/wallet/src/services/AssetsTracker.ts

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// eslint-disable no-console
12
import { Asset, Cardano } from '@cardano-sdk/core';
23
import { Assets } from '../types';
34
import { BalanceTracker, Milliseconds, TransactionsTracker } from './types';
@@ -26,8 +27,14 @@ import { newTransactions$ } from './TransactionsTracker';
2627
import chunk from 'lodash/chunk.js';
2728
import uniq from 'lodash/uniq.js';
2829

29-
const isAssetInfoComplete = (assetInfo: Asset.AssetInfo): boolean =>
30-
assetInfo.nftMetadata !== undefined && assetInfo.tokenMetadata !== undefined;
30+
const isAssetInfoComplete = (assetInfo: Asset.AssetInfo): boolean => {
31+
// eslint-disable-next-line no-console
32+
console.error('assetInfo', assetInfo);
33+
// eslint-disable-next-line no-console
34+
console.error('isAssetInfoComplete', assetInfo.nftMetadata !== undefined && assetInfo.tokenMetadata !== undefined);
35+
return assetInfo.nftMetadata !== undefined && assetInfo.tokenMetadata !== undefined;
36+
};
37+
3138
const isEveryAssetInfoComplete = (assetInfos: Asset.AssetInfo[]): boolean => assetInfos.every(isAssetInfoComplete);
3239

3340
/** Buffers the source Observable values emitted at the same time (within 1 ms) */
@@ -65,6 +72,9 @@ const splitCachedAndUncachedAssets = (
6572
for (const id of assetIds) {
6673
const cachedAssetInfo = cache.get(id);
6774

75+
// eslint-disable-next-line no-console
76+
console.error('cachedAssetInfo', cachedAssetInfo);
77+
6878
if (!cachedAssetInfo) {
6979
uncachedAssetIds.push(id);
7080
continue;
@@ -102,6 +112,11 @@ export const createAssetService =
102112
switchMap(([cache, totalValue]) => {
103113
const { cachedAssets, uncachedAssetIds } = splitCachedAndUncachedAssets(cache, totalValue, assetIds);
104114

115+
// eslint-disable-next-line no-console
116+
console.error('cachedAssets', cachedAssets);
117+
// eslint-disable-next-line no-console
118+
console.error('uncachedAssetIds', uncachedAssetIds);
119+
105120
if (uncachedAssetIds.length === 0) {
106121
return of([...cachedAssets.values()]);
107122
}
@@ -111,11 +126,20 @@ export const createAssetService =
111126
coldObservableProvider({
112127
onFatalError,
113128
pollUntil: isEveryAssetInfoComplete,
114-
provider: () =>
115-
assetProvider.getAssets({
116-
assetIds: assetIdsChunk,
117-
extraData: { nftMetadata: true, tokenMetadata: true }
118-
}),
129+
provider: () => {
130+
// eslint-disable-next-line no-console
131+
console.error('Fetching asset info for assetIds:', assetIdsChunk);
132+
return assetProvider
133+
.getAssets({
134+
assetIds: assetIdsChunk,
135+
extraData: { nftMetadata: true, tokenMetadata: true }
136+
})
137+
.then((assets) => {
138+
// eslint-disable-next-line no-console
139+
console.error('Fetched assets:', assets);
140+
return assets;
141+
});
142+
},
119143
retryBackoffConfig,
120144
trigger$: of(true) // fetch only once
121145
})
@@ -237,7 +261,11 @@ export const createAssetsTracker = (
237261
}),
238262
// Restart inner observable if there are new assets to be fetched,
239263
// otherwise the whole pipe will hang waiting for all assetInfos to resolve
240-
switchMap((assetIdsToFetch) => (assetIdsToFetch.length > 0 ? assetService(assetIdsToFetch) : of([]))),
264+
switchMap((assetIdsToFetch) => {
265+
// eslint-disable-next-line no-console
266+
console.error('QWEFDS Asset IDs to fetch:', assetIdsToFetch);
267+
return assetIdsToFetch.length > 0 ? assetService(assetIdsToFetch) : of([]);
268+
}),
241269
map((fetchedAssetInfos) => [...[...fetchedAssetInfoMap.values()].filter(isNotNil), ...fetchedAssetInfos]),
242270
distinctUntilChanged(deepEquals), // It optimizes to not process duplicate emissions of the assets
243271
tap((assetInfos) => logger.debug(`Got metadata for ${assetInfos.length} assets`)),

packages/wallet/src/services/ProviderTracker/ProviderStatusTracker.ts

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export interface ProviderStatusTrackerDependencies {
4545
logger: Logger;
4646
}
4747

48+
const logEmission = <T>(obs$: Observable<T>, name: string): Observable<T> =>
49+
// eslint-disable-next-line no-console
50+
obs$.pipe(tap((value) => console.debug(`DDDDDDDDDDDD ${name} emitted value:`, value)));
51+
4852
const getDefaultProviderSyncRelevantStats = ({
4953
stakePoolProvider,
5054
networkInfoProvider,
@@ -55,18 +59,19 @@ const getDefaultProviderSyncRelevantStats = ({
5559
drepProvider
5660
}: ProviderStatusTrackerDependencies): Observable<ProviderFnStats[]> =>
5761
combineLatest([
58-
networkInfoProvider.stats.ledgerTip$,
59-
networkInfoProvider.stats.protocolParameters$,
60-
networkInfoProvider.stats.genesisParameters$,
61-
networkInfoProvider.stats.eraSummaries$,
62-
assetProvider.stats.getAsset$,
63-
stakePoolProvider.stats.queryStakePools$,
64-
utxoProvider.stats.utxoByAddresses$,
65-
chainHistoryProvider.stats.transactionsByAddresses$,
66-
drepProvider.stats.getDRepInfo$,
67-
rewardsProvider.stats.rewardsHistory$,
68-
rewardsProvider.stats.rewardAccountBalance$
69-
]);
62+
logEmission(networkInfoProvider.stats.ledgerTip$, 'ledgerTip$'),
63+
logEmission(networkInfoProvider.stats.protocolParameters$, 'protocolParameters$'),
64+
logEmission(networkInfoProvider.stats.genesisParameters$, 'genesisParameters$'),
65+
logEmission(networkInfoProvider.stats.eraSummaries$, 'eraSummaries$'),
66+
logEmission(assetProvider.stats.getAsset$, 'getAsset$'),
67+
logEmission(stakePoolProvider.stats.queryStakePools$, 'queryStakePools$'),
68+
logEmission(utxoProvider.stats.utxoByAddresses$, 'utxoByAddresses$'),
69+
logEmission(chainHistoryProvider.stats.transactionsByAddresses$, 'transactionsByAddresses$'),
70+
logEmission(drepProvider.stats.getDRepInfo$, 'getDRepInfo$'),
71+
logEmission(rewardsProvider.stats.rewardsHistory$, 'rewardsHistory$'),
72+
logEmission(rewardsProvider.stats.rewardAccountBalance$, 'rewardAccountBalance$')
73+
// eslint-disable-next-line no-console
74+
]).pipe(tap(() => console.debug('combineLatest emitted all dependencies')));
7075

7176
export interface ProviderStatusTrackerInternals {
7277
/**
@@ -102,13 +107,27 @@ export const createProviderStatusTracker = (
102107
debounceTime(1),
103108
skipWhile((allStats) => allStats.some(({ initialized }) => !initialized)),
104109
take(1),
105-
tap(() => logger.debug('All stats are initialized')),
110+
// eslint-disable-next-line no-console
111+
tap(() => console.error('All stats are initialized')),
106112
mergeMap(() => EMPTY)
107113
);
108114
const isSettled$ = new TrackerSubject<boolean>(
109-
concat(of(false), statsReady$, isAnyRequestPending$.pipe(map((pending) => !pending))).pipe(
115+
concat(
116+
// eslint-disable-next-line no-console
117+
of(false).pipe(tap(() => console.error('isSettled$ initialized with false'))),
118+
// eslint-disable-next-line no-console
119+
statsReady$.pipe(tap(() => console.error('statsReady$ emitted'))),
120+
isAnyRequestPending$.pipe(
121+
// eslint-disable-next-line no-console
122+
tap((pending) => console.error('isAnyRequestPending$', { pending })),
123+
map((pending) => !pending),
124+
// eslint-disable-next-line no-console
125+
tap((notPending) => console.error('isAnyRequestPending$ mapped to notPending', { notPending }))
126+
)
127+
).pipe(
110128
distinctUntilChanged(),
111-
tap((isSettled) => logger.debug('isSettled', isSettled))
129+
// eslint-disable-next-line no-console
130+
tap((isSettled) => console.error('0000000000000000000000 isSettled updated:', { isSettled }))
112131
)
113132
);
114133
const isUpToDate$ = new TrackerSubject<boolean>(
@@ -119,7 +138,8 @@ export const createProviderStatusTracker = (
119138
switchMap(() => concat(of(true), timer(consideredOutOfSyncAfter).pipe(map(() => false)))),
120139
distinctUntilChanged()
121140
)
122-
).pipe(tap((isUpToDate) => logger.debug('isUpToDate', isUpToDate)))
141+
// eslint-disable-next-line no-console
142+
).pipe(tap((isUpToDate) => console.error('isUpToDate', isUpToDate)))
123143
);
124144
return {
125145
isAnyRequestPending$,

0 commit comments

Comments
 (0)