mirror of
https://github.com/benjamin-wilson/public-pool.git
synced 2026-09-29 09:05:06 -07:00
revert stale job retention
This commit is contained in:
@@ -25,7 +25,6 @@ export class MiningJob {
|
||||
public jobTemplateId: string;
|
||||
public networkDifficulty: number;
|
||||
public creation: number;
|
||||
public retiredAt?: number;
|
||||
|
||||
constructor(
|
||||
private network: bitcoinjs.networks.Network,
|
||||
|
||||
@@ -550,19 +550,6 @@ export class StratumV1Client {
|
||||
return false;
|
||||
}
|
||||
|
||||
const classification = this.stratumV1JobsService.classifyJobForShare(job);
|
||||
if (classification === 'stale-rejected') {
|
||||
const err = new StratumErrorMessage(
|
||||
submission.id,
|
||||
eStratumErrorCode.JobNotFound,
|
||||
'stale').response();
|
||||
const success = await this.write(err);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const submissionHash = [
|
||||
submission.jobId,
|
||||
submission.extraNonce2,
|
||||
|
||||
@@ -47,7 +47,7 @@ describe('StratumV1JobsService', () => {
|
||||
expect(service.getJobTemplateById('1')).toBe(jobTemplate);
|
||||
});
|
||||
|
||||
it('should retire jobs when the block height changes', async () => {
|
||||
it('should clear jobs when the block height changes', async () => {
|
||||
const firstTemplate = await firstValueFrom(service.newMiningJob$);
|
||||
service.addJob({ jobId: 'old-job', creation: Date.now() } as any);
|
||||
|
||||
@@ -57,27 +57,18 @@ describe('StratumV1JobsService', () => {
|
||||
const jobTemplate = await nextTemplate;
|
||||
|
||||
expect(jobTemplate.blockData.clearJobs).toBe(true);
|
||||
expect(service.getJobById('old-job')).toEqual(expect.objectContaining({
|
||||
jobId: 'old-job',
|
||||
retiredAt: Date.now()
|
||||
}));
|
||||
expect(service.getJobTemplateById(firstTemplate.blockData.id).blockData.retiredAt).toBe(Date.now());
|
||||
expect(service.getJobById('old-job')).toBeUndefined();
|
||||
expect(service.getJobTemplateById(firstTemplate.blockData.id)).toBeUndefined();
|
||||
expect(service.getJobTemplateById(jobTemplate.blockData.id)).toBe(jobTemplate);
|
||||
});
|
||||
|
||||
it('should age retired jobs and templates after the retention window', async () => {
|
||||
const firstTemplate = await firstValueFrom(service.newMiningJob$);
|
||||
it('should age old jobs and templates after five minutes', async () => {
|
||||
await firstValueFrom(service.newMiningJob$);
|
||||
const oldCreation = Date.now() - (1000 * 60 * 11);
|
||||
const retiredAt = Date.now() - (1000 * 60 * 11);
|
||||
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 }
|
||||
service.jobs['old-job'] = { jobId: 'old-job', creation: oldCreation } as any;
|
||||
service.blocks['old-template'] = {
|
||||
blockData: { creation: oldCreation }
|
||||
} as any;
|
||||
(service as any).trackBlock(`old-template-${i}`);
|
||||
}
|
||||
|
||||
bitcoinRpcService.miningInfo.blocks = MockRecording1.BLOCK_TEMPLATE.height;
|
||||
const nextTemplate = firstValueFrom(service.newMiningJob$.pipe(skip(1)));
|
||||
@@ -85,22 +76,11 @@ describe('StratumV1JobsService', () => {
|
||||
const jobTemplate = await nextTemplate;
|
||||
|
||||
expect(jobTemplate.blockData.clearJobs).toBe(false);
|
||||
expect(service.getJobById('old-job-4')).toBeUndefined();
|
||||
expect(service.getJobTemplateById('old-template-4')).toBeUndefined();
|
||||
expect(service.getJobById('old-job')).toBeUndefined();
|
||||
expect(service.getJobTemplateById('old-template')).toBeUndefined();
|
||||
expect(service.getJobTemplateById(jobTemplate.blockData.id)).toBe(jobTemplate);
|
||||
});
|
||||
|
||||
it('should classify retired jobs inside and outside the stale grace window', () => {
|
||||
const job = { jobId: '1', creation: Date.now(), retiredAt: Date.now() - 1000 } as any;
|
||||
|
||||
expect(service.classifyJobForShare(job, Date.now())).toBe('stale-creditable');
|
||||
|
||||
job.retiredAt = Date.now() - 6000;
|
||||
|
||||
expect(service.classifyJobForShare(job, Date.now())).toBe('stale-rejected');
|
||||
expect(service.classifyJobForShare({ jobId: '2', creation: Date.now() } as any, Date.now())).toBe('active');
|
||||
});
|
||||
|
||||
it('should increment job ids when jobs are added', () => {
|
||||
expect(service.getNextId()).toBe('1');
|
||||
|
||||
|
||||
@@ -18,14 +18,9 @@ export interface IJobTemplate {
|
||||
networkDifficulty: number;
|
||||
height: number;
|
||||
clearJobs: boolean;
|
||||
retiredAt?: number;
|
||||
};
|
||||
}
|
||||
|
||||
const STALE_GRACE_MS = parseInt(process.env.STRATUM_STALE_GRACE_MS) || 5000;
|
||||
const MIN_RETAINED = 3;
|
||||
export { STALE_GRACE_MS };
|
||||
|
||||
@Injectable()
|
||||
export class StratumV1JobsService {
|
||||
|
||||
@@ -36,11 +31,6 @@ export class StratumV1JobsService {
|
||||
public blocks: { [id: number]: IJobTemplate } = {};
|
||||
|
||||
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
|
||||
@@ -121,7 +111,6 @@ 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 })
|
||||
)
|
||||
@@ -153,78 +142,32 @@ export class StratumV1JobsService {
|
||||
|
||||
public cleanup(clearJobs: boolean, now: number = Date.now()) {
|
||||
if (clearJobs) {
|
||||
for (const id of this.blockOrder) {
|
||||
const block = this.blocks[id];
|
||||
if (block != null && block.blockData.retiredAt === undefined) {
|
||||
block.blockData.retiredAt = now;
|
||||
}
|
||||
}
|
||||
for (const jobId of this.jobOrder) {
|
||||
const job = this.jobs[jobId];
|
||||
if (job != null && job.retiredAt === undefined) {
|
||||
job.retiredAt = now;
|
||||
this.blocks = {};
|
||||
this.jobs = {};
|
||||
return;
|
||||
}
|
||||
|
||||
let templatesDeleted = 0;
|
||||
let jobsDeleted = 0;
|
||||
|
||||
for (const templateId in this.blocks) {
|
||||
if (now - this.blocks[templateId].blockData.creation > (1000 * 60 * 5)) {
|
||||
delete this.blocks[templateId];
|
||||
templatesDeleted++;
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
for (const jobId in this.jobs) {
|
||||
if (now - this.jobs[jobId].creation > (1000 * 60 * 5)) {
|
||||
delete this.jobs[jobId];
|
||||
jobsDeleted++;
|
||||
}
|
||||
|
||||
private ageEntries<T>(
|
||||
map: Record<string, T>,
|
||||
order: string[],
|
||||
orderSet: Set<string>,
|
||||
now: number,
|
||||
getCreation: (entry: T) => number,
|
||||
getRetiredAt: (entry: T) => number | undefined,
|
||||
): void {
|
||||
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;
|
||||
}
|
||||
//console.log(`Deleted ${templatesDeleted} templates and ${jobsDeleted} jobs.`)
|
||||
}
|
||||
|
||||
public addJob(job: MiningJob) {
|
||||
this.jobs[job.jobId] = job;
|
||||
this.trackJob(job.jobId);
|
||||
this.latestJobId++;
|
||||
}
|
||||
|
||||
@@ -232,13 +175,6 @@ export class StratumV1JobsService {
|
||||
return this.jobs[jobId];
|
||||
}
|
||||
|
||||
public classifyJobForShare(job: MiningJob, now: number = Date.now()): 'active' | 'stale-creditable' | 'stale-rejected' {
|
||||
if (job.retiredAt === undefined) {
|
||||
return 'active';
|
||||
}
|
||||
return (now - job.retiredAt) <= STALE_GRACE_MS ? 'stale-creditable' : 'stale-rejected';
|
||||
}
|
||||
|
||||
public getNextTemplateId() {
|
||||
return this.latestJobTemplateId.toString(16);
|
||||
}
|
||||
@@ -246,20 +182,4 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user