optimizations

This commit is contained in:
Ben
2026-05-06 21:24:04 -04:00
parent d9fa933825
commit 703546719c
3 changed files with 64 additions and 37 deletions
+13 -20
View File
@@ -3,7 +3,6 @@ import * as bitcoinjs from 'bitcoinjs-lib';
import { IJobTemplate } from '../services/stratum-v1-jobs.service';
import { eResponseMethod } from './enums/eResponseMethod';
import { IMiningNotify } from './stratum-messages/IMiningNotify';
import { TOTAL_EXTRANONCE_SIZE_BYTES } from './stratum.constants';
const MAX_BLOCK_WEIGHT = 4000000;
@@ -21,6 +20,7 @@ export class MiningJob {
private coinbasePart1Buffer: Buffer;
private coinbasePart2Buffer: Buffer;
private merkleBranchBuffers: Buffer[];
private notifyStaticParams: string;
public jobTemplateId: string;
public networkDifficulty: number;
@@ -89,7 +89,16 @@ export class MiningJob {
this.coinbasePart2 = serializedCoinbaseTx.slice(partOneIndex);
this.coinbasePart1Buffer = Buffer.from(this.coinbasePart1, 'hex');
this.coinbasePart2Buffer = Buffer.from(this.coinbasePart2, 'hex');
this.notifyStaticParams = JSON.stringify([
this.swapEndianWords(jobTemplate.block.prevHash).toString('hex'),
this.coinbasePart1,
this.coinbasePart2,
jobTemplate.merkle_branch,
jobTemplate.block.version.toString(16),
jobTemplate.block.bits.toString(16),
jobTemplate.block.timestamp.toString(16),
jobTemplate.blockData.clearJobs
]).slice(1);
}
@@ -108,6 +117,7 @@ export class MiningJob {
job.coinbasePart1Buffer = this.coinbasePart1Buffer;
job.coinbasePart2Buffer = this.coinbasePart2Buffer;
job.merkleBranchBuffers = this.merkleBranchBuffers;
job.notifyStaticParams = this.notifyStaticParams;
job.jobTemplateId = this.jobTemplateId;
job.networkDifficulty = this.networkDifficulty;
job.creation = new Date().getTime();
@@ -254,24 +264,7 @@ export class MiningJob {
}
public response(jobTemplate: IJobTemplate): string {
const job: IMiningNotify = {
id: null,
method: eResponseMethod.MINING_NOTIFY,
params: [
this.jobId,
this.swapEndianWords(jobTemplate.block.prevHash).toString('hex'),
this.coinbasePart1,
this.coinbasePart2,
jobTemplate.merkle_branch,
jobTemplate.block.version.toString(16),
jobTemplate.block.bits.toString(16),
jobTemplate.block.timestamp.toString(16),
jobTemplate.blockData.clearJobs
]
};
return JSON.stringify(job) + '\n';
return `{"id":null,"method":"${eResponseMethod.MINING_NOTIFY}","params":[${JSON.stringify(this.jobId)},${this.notifyStaticParams}}\n`;
}
+5 -2
View File
@@ -66,14 +66,17 @@ describe('StratumV1JobsService', () => {
});
it('should age retired jobs and templates after the retention window', async () => {
await firstValueFrom(service.newMiningJob$);
const firstTemplate = await firstValueFrom(service.newMiningJob$);
const oldCreation = Date.now() - (1000 * 60 * 11);
const retiredAt = Date.now() - (1000 * 60 * 11);
for (let i = 0; i < 5; i++) {
firstTemplate.blockData.retiredAt = retiredAt;
for (let i = 4; i >= 0; i--) {
service.jobs[`old-job-${i}`] = { jobId: `old-job-${i}`, creation: oldCreation - i, retiredAt } as any;
(service as any).trackJob(`old-job-${i}`);
service.blocks[`old-template-${i}`] = {
blockData: { creation: oldCreation - i, retiredAt }
} as any;
(service as any).trackBlock(`old-template-${i}`);
}
bitcoinRpcService.miningInfo.blocks = MockRecording1.BLOCK_TEMPLATE.height;
+46 -15
View File
@@ -37,6 +37,10 @@ export class StratumV1JobsService {
private lastBlockHeight = 0;
private jobRetentionMs = parseInt(process.env.JOB_RETENTION_MS) || 600000;
private jobOrder: string[] = [];
private blockOrder: string[] = [];
private jobOrderSet = new Set<string>();
private blockOrderSet = new Set<string>();
constructor(
private readonly bitcoinRpcService: BitcoinRpcService
@@ -117,6 +121,7 @@ export class StratumV1JobsService {
tap((data) => {
this.cleanup(data.blockData.clearJobs);
this.blocks[data.blockData.id] = data;
this.trackBlock(data.blockData.id);
}),
shareReplay({ refCount: true, bufferSize: 1 })
)
@@ -148,15 +153,15 @@ export class StratumV1JobsService {
public cleanup(clearJobs: boolean, now: number = Date.now()) {
if (clearJobs) {
for (const id in this.blocks) {
for (const id of this.blockOrder) {
const block = this.blocks[id];
if (block.blockData.retiredAt === undefined) {
if (block != null && block.blockData.retiredAt === undefined) {
block.blockData.retiredAt = now;
}
}
for (const jobId in this.jobs) {
for (const jobId of this.jobOrder) {
const job = this.jobs[jobId];
if (job.retiredAt === undefined) {
if (job != null && job.retiredAt === undefined) {
job.retiredAt = now;
}
}
@@ -164,12 +169,16 @@ export class StratumV1JobsService {
this.ageEntries(
this.blocks,
this.blockOrder,
this.blockOrderSet,
now,
entry => entry.blockData.creation,
entry => entry.blockData.retiredAt,
);
this.ageEntries(
this.jobs,
this.jobOrder,
this.jobOrderSet,
now,
entry => entry.creation,
entry => entry.retiredAt,
@@ -178,37 +187,44 @@ export class StratumV1JobsService {
private ageEntries<T>(
map: Record<string, T>,
order: string[],
orderSet: Set<string>,
now: number,
getCreation: (entry: T) => number,
getRetiredAt: (entry: T) => number | undefined,
): void {
const ids = Object.keys(map);
if (ids.length <= MIN_RETAINED) {
return;
}
const candidatesForGC = ids
.slice()
.sort((a, b) => getCreation(map[b]) - getCreation(map[a]))
.slice(MIN_RETAINED);
for (const id of candidatesForGC) {
while (order.length > MIN_RETAINED) {
const id = order[0];
const entry = map[id];
if (entry == null) {
order.shift();
orderSet.delete(id);
continue;
}
const retiredAt = getRetiredAt(entry);
if (retiredAt !== undefined && now - retiredAt > this.jobRetentionMs) {
delete map[id];
order.shift();
orderSet.delete(id);
continue;
}
if (retiredAt === undefined && now - getCreation(entry) > this.jobRetentionMs * 2) {
delete map[id];
order.shift();
orderSet.delete(id);
continue;
}
break;
}
}
public addJob(job: MiningJob) {
this.jobs[job.jobId] = job;
this.trackJob(job.jobId);
this.latestJobId++;
}
@@ -230,5 +246,20 @@ export class StratumV1JobsService {
return this.latestJobId.toString(16);
}
private trackJob(jobId: string): void {
if (this.jobOrderSet.has(jobId)) {
return;
}
this.jobOrderSet.add(jobId);
this.jobOrder.push(jobId);
}
private trackBlock(blockId: string): void {
if (this.blockOrderSet.has(blockId)) {
return;
}
this.blockOrderSet.add(blockId);
this.blockOrder.push(blockId);
}
}