Files
public-pool/src/models/StratumV1ClientStatistics.ts
T

111 lines
3.2 KiB
TypeScript

import { ClientStatisticsService } from '../ORM/client-statistics/client-statistics.service';
import { ClientEntity } from '../ORM/client/client.entity';
const CACHE_SIZE = 30;
const TARGET_SUBMISSION_PER_SECOND = 10;
const MIN_DIFF = 0.00001;
export class StratumV1ClientStatistics {
private shareBacklog: number = 0;
private submissionCacheStart: Date;
private submissionCache = [];
constructor(
private readonly clientStatisticsService: ClientStatisticsService
) {
this.submissionCacheStart = new Date();
}
public async saveShares(client: ClientEntity) {
if (client == null || client.address == null || client.clientName == null || client.sessionId == null) {
return;
}
// 10 min
var coeff = 1000 * 60 * 10;
var date = new Date();
var rounded = new Date(Math.floor(date.getTime() / coeff) * coeff);
await this.clientStatisticsService.save({
time: rounded.getTime(),
shares: this.shareBacklog,
address: client.address,
clientName: client.clientName,
sessionId: client.sessionId
});
this.shareBacklog = 0;
}
// We don't want to save them here because it can be DB intensive, stead do it every once in
// awhile with saveShares()
public async addShares(targetDifficulty: number) {
if (this.submissionCache.length > CACHE_SIZE) {
this.submissionCache.shift();
}
this.submissionCache.push({
time: new Date(),
difficulty: targetDifficulty,
});
this.shareBacklog += targetDifficulty;
}
public getSuggestedDifficulty(clientDifficulty: number) {
// miner hasn't submitted shares in one minute
if (this.submissionCache.length < 5) {
if ((new Date().getTime() - this.submissionCacheStart.getTime()) / 1000 > 60) {
return this.nearestPowerOfTwo(clientDifficulty / 6);
} else {
return null;
}
}
const sum = this.submissionCache.reduce((pre, cur) => {
pre += cur.difficulty;
return pre;
}, 0);
const diffSeconds = (this.submissionCache[this.submissionCache.length - 1].time.getTime() - this.submissionCache[0].time.getTime()) / 1000;
const difficultyPerSecond = sum / diffSeconds;
const targetDifficulty = difficultyPerSecond * TARGET_SUBMISSION_PER_SECOND;
if ((clientDifficulty * 2) < targetDifficulty || (clientDifficulty / 2) > targetDifficulty) {
return this.nearestPowerOfTwo(targetDifficulty)
}
return null;
}
private nearestPowerOfTwo(val): number {
if (val === 0) {
return null;
}
if (val < MIN_DIFF) {
return MIN_DIFF;
}
let x = val | (val >> 1);
x = x | (x >> 2);
x = x | (x >> 4);
x = x | (x >> 8);
x = x | (x >> 16);
x = x | (x >> 32);
const res = x - (x >> 1);
if (res == 0 && val * 100 < MIN_DIFF) {
return MIN_DIFF;
}
if (res == 0) {
return this.nearestPowerOfTwo(val * 100) / 100;
}
return res;
}
}