Speed up template publication and share validation

This commit is contained in:
Ben
2026-07-11 23:33:24 -04:00
parent 126b05224f
commit 4f29269fed
34 changed files with 9789 additions and 724 deletions
+107 -1
View File
@@ -1,3 +1,5 @@
import { Subject } from 'rxjs';
import { StratumV1Service } from './stratum-v1.service';
describe('StratumV1Service', () => {
@@ -16,6 +18,7 @@ describe('StratumV1Service', () => {
let userAgentReportService;
let stratumV2Service;
let redisMessagingService;
let miningJobs: Subject<any>;
let consoleLogSpy: jest.SpyInstance;
let consoleWarnSpy: jest.SpyInstance;
@@ -32,13 +35,14 @@ describe('StratumV1Service', () => {
createClient: jest.fn()
};
redisMessagingService = {};
miningJobs = new Subject();
service = new StratumV1Service(
{} as any,
clientService,
{} as any,
{} as any,
{} as any,
{} as any,
{ newMiningJob$: miningJobs.asObservable() } as any,
{} as any,
stratumV2Service as any,
userAgentReportService as any,
@@ -101,6 +105,108 @@ describe('StratumV1Service', () => {
expect(startSecureSocketServerSpy).toHaveBeenCalledWith(14333, 'pplns');
});
it('should fan out each job once through the worker broadcaster', async () => {
process.env.MASTER = 'false';
process.env.STRATUM_PORTS = '';
process.env.STRATUM_SECURE = 'false';
const client = {
broadcastMiningJob: jest.fn().mockReturnValue({
status: 'written',
bytes: 500,
bufferedBytes: 0,
}),
};
(service as any).clients.add(client);
await service.onModuleInit();
const job = {
blockData: {
id: 'a',
height: 900001,
jobType: 'full',
isNewBlock: true,
clearJobs: true,
},
};
miningJobs.next(job);
expect(client.broadcastMiningJob).toHaveBeenCalledTimes(1);
expect(client.broadcastMiningJob).toHaveBeenCalledWith(job);
expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('stratum_job_fanout'));
service.onModuleDestroy();
});
it('enqueues a 100,000-client fanout without per-client async serialization', () => {
const clientCount = 100_000;
let writes = 0;
const broadcastMiningJob = () => {
writes++;
return { status: 'written', bytes: 256, bufferedBytes: 0 };
};
for (let index = 0; index < clientCount; index++) {
(service as any).clients.add({ broadcastMiningJob });
}
const job = {
blockData: {
id: 'load',
height: 900001,
jobType: 'empty',
isNewBlock: true,
clearJobs: true,
notificationEventId: 'load-test',
notificationPublishedAtMs: Date.now(),
},
};
(service as any).broadcastMiningJob(job);
const trace = JSON.parse(consoleLogSpy.mock.calls.at(-1)?.[0]);
expect(writes).toBe(clientCount);
expect(trace).toEqual(expect.objectContaining({
event: 'stratum_job_fanout',
eventId: 'load-test',
clients: clientCount,
written: clientCount,
}));
expect(trace.milestoneMs).toEqual(expect.objectContaining({
p50: expect.any(Number),
p95: expect.any(Number),
p99: expect.any(Number),
}));
expect(trace.totalMs).toBeLessThan(1_000);
});
it('reports a buffer-limited client as closed without counting an unwritten job', () => {
(service as any).clients.add({
broadcastMiningJob: jest.fn().mockReturnValue({
status: 'closed',
bytes: 0,
bufferedBytes: 262_144,
}),
});
const job = {
blockData: {
id: 'buffer-limit',
height: 900001,
jobType: 'empty',
isNewBlock: true,
clearJobs: true,
},
};
(service as any).broadcastMiningJob(job);
const trace = JSON.parse(consoleLogSpy.mock.calls.at(-1)?.[0]);
expect(trace).toEqual(expect.objectContaining({
clients: 1,
closed: 1,
written: 0,
backpressured: 0,
bytesQueued: 0,
maxBufferedBytes: 262_144,
}));
});
it('should pause listeners when worker backpressure is high', () => {
const close = jest.fn((callback?: (error?: Error) => void) => callback?.());
(service as any).listeners.push({