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