diff --git a/src/controllers/client/client.controller.spec.ts b/src/controllers/client/client.controller.spec.ts index 18b00ff..a489ca0 100644 --- a/src/controllers/client/client.controller.spec.ts +++ b/src/controllers/client/client.controller.spec.ts @@ -9,6 +9,14 @@ import { ClientController } from './client.controller'; describe('ClientController', () => { let controller: ClientController; + let addressSettingsService: { getSettings: jest.Mock }; + let shareAccountingService: { + getAddressSummary: jest.Mock; + getWorkerGroupSummary: jest.Mock; + getSessionSummary: jest.Mock; + getSessionSummaries: jest.Mock; + }; + let redisMessagingService: { getClientPresenceByAddress: jest.Mock }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -56,9 +64,40 @@ describe('ClientController', () => { }).compile(); controller = module.get(ClientController); + addressSettingsService = module.get(AddressSettingsService); + shareAccountingService = module.get(ShareAccountingService); + redisMessagingService = module.get(RedisMessagingService); }); it('should be defined', () => { expect(controller).toBeDefined(); }); + + it('should expose the existing address best difficulty in accounting when rollup best is empty', async () => { + redisMessagingService.getClientPresenceByAddress.mockResolvedValue([ + { + clientId: '92f5302f-5e32-487e-af67-f56fd78b13c7', + sessionId: 'abcd1234', + clientName: 'worker', + bestDifficulty: 64, + hashRate: 1024, + startTime: '2026-06-08T12:00:00.000Z', + lastSeen: '2026-06-08T12:10:00.000Z', + }, + ]); + addressSettingsService.getSettings.mockResolvedValue({ bestDifficulty: 4096 }); + shareAccountingService.getSessionSummaries.mockResolvedValue(new Map()); + shareAccountingService.getAddressSummary.mockResolvedValue({ + totalAcceptedShares: 10, + totalCreditedDifficulty: 100, + bestSubmissionDifficulty: 0, + }); + + await expect(controller.getClientInfo('bc1qtest')).resolves.toEqual(expect.objectContaining({ + bestDifficulty: 4096, + accounting: expect.objectContaining({ + bestSubmissionDifficulty: 4096, + }), + })); + }); }); diff --git a/src/controllers/client/client.controller.ts b/src/controllers/client/client.controller.ts index 31f1d6f..14010ed 100644 --- a/src/controllers/client/client.controller.ts +++ b/src/controllers/client/client.controller.ts @@ -27,10 +27,13 @@ export class ClientController { const addressSettings = process.env.API_ONLY === 'true' ? null : await this.addressSettingsService.getSettings(address, false); - const accounting = await this.shareAccountingService.getAddressSummary(address); const bestDifficulty = addressSettings?.bestDifficulty ?? workers.reduce((best, worker) => { return Math.max(best, Number(worker.bestDifficulty ?? 0)); }, 0); + const accounting = this.withBestSubmissionDifficulty( + await this.shareAccountingService.getAddressSummary(address), + bestDifficulty, + ); const response = { bestDifficulty, @@ -76,7 +79,10 @@ export class ClientController { }, 0); const chartData = await this.clientStatisticsService.getChartDataForGroup(address, workerName); - const accounting = await this.shareAccountingService.getWorkerGroupSummary(address, workerName); + const accounting = this.withBestSubmissionDifficulty( + await this.shareAccountingService.getWorkerGroupSummary(address, workerName), + bestDifficulty, + ); const response = { name: workerName, @@ -106,7 +112,10 @@ export class ClientController { return new NotFoundException(); } const chartData = await this.clientStatisticsService.getChartDataForSession(worker.id); - const accounting = await this.shareAccountingService.getSessionSummary(worker.id); + const accounting = this.withBestSubmissionDifficulty( + await this.shareAccountingService.getSessionSummary(worker.id), + worker.bestDifficulty, + ); const response = { sessionId: worker.sessionId, @@ -118,4 +127,21 @@ export class ClientController { } return response; } + + private withBestSubmissionDifficulty( + accounting: T, + fallbackBestDifficulty: unknown, + ): T { + const existing = Number(accounting?.bestSubmissionDifficulty ?? 0); + const fallback = Number(fallbackBestDifficulty ?? 0); + + if (!Number.isFinite(fallback) || fallback <= existing) { + return accounting; + } + + return { + ...accounting, + bestSubmissionDifficulty: fallback, + }; + } }