diff --git a/packages/wallet/src/SingleAddressWallet.ts b/packages/wallet/src/SingleAddressWallet.ts index 64e152c4b24..4897f94c15a 100644 --- a/packages/wallet/src/SingleAddressWallet.ts +++ b/packages/wallet/src/SingleAddressWallet.ts @@ -171,7 +171,6 @@ export class SingleAddressWallet implements ObservableWallet { }: SingleAddressWalletDependencies ) { this.#logger = contextLogger(logger, this.name); - this.#logger.debug('Initializing...'); this.#inputSelector = inputSelector; @@ -205,11 +204,14 @@ export class SingleAddressWallet implements ObservableWallet { distinctUntilChanged(groupedAddressesEquals), tap( // derive an address if none available - (addresses) => - addresses.length === 0 && - void keyAgent - .deriveAddress({ index: 0, type: AddressType.External }) - .catch(() => this.#logger.error('Failed to derive address')) + (addresses) => { + if (addresses.length === 0) { + this.#logger.debug('No addresses available; deriving one'); + void keyAgent + .deriveAddress({ index: 0, type: AddressType.External }) + .catch(() => this.#logger.error('Failed to derive address')); + } + } ), filter((addresses) => addresses.length > 0), tap(stores.addresses.set.bind(stores.addresses)) @@ -218,9 +220,13 @@ export class SingleAddressWallet implements ObservableWallet { ); this.name = name; - const cancel$ = connectionStatusTracker$.pipe(filter((status) => status === ConnectionStatus.down)); + const cancel$ = connectionStatusTracker$.pipe( + tap((status) => (status === ConnectionStatus.up ? 'Connection UP' : 'Connection DOWN')), + filter((status) => status === ConnectionStatus.down) + ); this.#tip$ = this.tip$ = new TipTracker({ connectionStatus$: connectionStatusTracker$, + logger: contextLogger(this.#logger, 'tip$'), maxPollInterval: maxInterval, minPollInterval: pollInterval, provider$: coldObservableProvider({ @@ -336,6 +342,7 @@ export class SingleAddressWallet implements ObservableWallet { stores.assets ); this.util = createWalletUtil(this); + this.#logger.debug('Created'); } async getName(): Promise { diff --git a/packages/wallet/src/services/TipTracker.ts b/packages/wallet/src/services/TipTracker.ts index 203ee013d3c..15883ec6f63 100644 --- a/packages/wallet/src/services/TipTracker.ts +++ b/packages/wallet/src/services/TipTracker.ts @@ -17,8 +17,10 @@ import { startWith, switchMap, takeUntil, + tap, timeout } from 'rxjs'; +import { Logger } from 'ts-log'; import { Milliseconds } from './types'; import { SyncStatus } from '../types'; export interface TipTrackerProps { @@ -31,6 +33,7 @@ export interface TipTrackerProps { */ minPollInterval: Milliseconds; maxPollInterval: Milliseconds; + logger: Logger; } export interface TipTrackerInternals { @@ -42,9 +45,10 @@ const triggerOrInterval$ = (trigger$: Observable, interval: numb export class TipTracker extends PersistentDocumentTrackerSubject { #externalTrigger$ = new Subject(); + #logger: Logger; constructor( - { provider$, minPollInterval, maxPollInterval, store, syncStatus, connectionStatus$ }: TipTrackerProps, + { provider$, minPollInterval, maxPollInterval, store, syncStatus, connectionStatus$, logger }: TipTrackerProps, { externalTrigger$ = new Subject() }: TipTrackerInternals = {} ) { super( @@ -62,20 +66,34 @@ export class TipTracker extends PersistentDocumentTrackerSubject { connectionStatus$ ]).pipe( // Throttle syncing by interval, cancel ongoing request on external trigger + tap(([isSettled, connectionStatus]) => { + if (connectionStatus === ConnectionStatus.down) { + // REVIEW: slightly redundant since connection debug messages are already recorded separately + logger.debug('Connection down. Skipping request'); + } else { + logger.debug(isSettled === null ? 'Initial request' : 'Start request'); + } + }), exhaustMap(([_, connectionStatus]) => connectionStatus === ConnectionStatus.down ? EMPTY : provider$.pipe(takeUntil(externalTrigger$)) ), - distinctUntilChanged(tipEquals) + distinctUntilChanged(tipEquals), + tap((tip) => logger.debug('Fetched new tip', tip)) ), // Always immediately restart request on external trigger - externalTrigger$.pipe(switchMap(() => provider$)) + externalTrigger$.pipe( + switchMap(() => provider$), + tap((tip) => logger.debug('External trigger fetched tip', tip)) + ) ).pipe(finalize(() => this.#externalTrigger$.complete())), store ); this.#externalTrigger$ = externalTrigger$; + this.#logger = logger; } sync() { + this.#logger.debug('Manual sync triggered'); this.#externalTrigger$.next(); } } diff --git a/packages/wallet/test/services/TipTracker.test.ts b/packages/wallet/test/services/TipTracker.test.ts index 043419ed8e8..32b915adbb8 100644 --- a/packages/wallet/test/services/TipTracker.test.ts +++ b/packages/wallet/test/services/TipTracker.test.ts @@ -4,6 +4,7 @@ import { InMemoryDocumentStore } from '../../src/persistence'; import { Milliseconds, SyncStatus } from '../../src'; import { Observable, firstValueFrom, of } from 'rxjs'; import { createTestScheduler } from '@cardano-sdk/util-dev'; +import { dummyLogger } from 'ts-log'; const stubObservableProvider = (...calls: Observable[]) => { let numCall = 0; @@ -26,6 +27,7 @@ describe('TipTracker', () => { const pollInterval: Milliseconds = 1; // delays emission after trigger let store: InMemoryDocumentStore; let connectionStatus$: Observable; + const logger = dummyLogger; beforeEach(() => { store = new InMemoryDocumentStore(); @@ -43,6 +45,7 @@ describe('TipTracker', () => { ); const tracker$ = new TipTracker({ connectionStatus$, + logger, maxPollInterval: Number.MAX_VALUE, minPollInterval: pollInterval, provider$, @@ -63,6 +66,7 @@ describe('TipTracker', () => { const provider$ = cold('|'); const tracker$ = new TipTracker({ connectionStatus$: connectionStatusOffOn$, + logger, maxPollInterval: Number.MAX_VALUE, minPollInterval: pollInterval, provider$, @@ -88,6 +92,7 @@ describe('TipTracker', () => { ); const tracker$ = new TipTracker({ connectionStatus$, + logger, maxPollInterval: Number.MAX_VALUE, minPollInterval: pollInterval, provider$, @@ -110,6 +115,7 @@ describe('TipTracker', () => { ); const tracker$ = new TipTracker({ connectionStatus$, + logger, maxPollInterval: 6, minPollInterval: pollInterval, provider$, @@ -132,6 +138,7 @@ describe('TipTracker', () => { const provider$ = stubObservableProvider(cold('x|', mockTips), cold('a|', mockTips)); const tracker$ = new TipTracker({ connectionStatus$: connectionStatusMock$, + logger, maxPollInterval: Number.MAX_VALUE, minPollInterval: 0, provider$, @@ -149,6 +156,7 @@ describe('TipTracker', () => { const provider$ = cold('x|', mockTips); const tracker$ = new TipTracker({ connectionStatus$: connectionStatusMock$, + logger, maxPollInterval: 6, minPollInterval: 0, provider$,