foxy-proxy
Version:
A Proof of Capacity proxy which supports solo and pool mining upstreams.
187 lines (160 loc) • 5.31 kB
JavaScript
const database = require('../../../models');
const util = require('../util');
const cache = require('../../services/cache');
const roundPopulator = require('../../services/round-populator');
const coinUtil = require('../../coin-util');
module.exports = (upstreamClass) => class StatsMixin extends upstreamClass {
constructor() {
super();
this.totalCapacity = 0;
}
getBestDL() {
return util.getBestDL(this.deadlines);
}
getConnectionStats() {
return {
connected: this.connected !== undefined ? this.connected : true,
connectionQuality: this.connectionQuality !== undefined ? this.connectionQuality : 100,
};
}
getCurrentRoundStats() {
const bestDL = this.getBestDL();
return {
blockNumber: this.miningInfo.height,
netDiff: this.miningInfo.modifiedNetDiff,
roundStart: this.roundStart,
bestDL: bestDL ? coinUtil.modifyDeadline(bestDL.toNumber(), this.upstreamConfig.coin) : null,
};
}
async getHistoricalStats() {
const estimatedCapacityInTB = await this.getEstimatedCapacity();
const historicalRounds = await this.getHistoricalRounds();
return {
estimatedCapacityInTB,
roundsWon: historicalRounds.filter(round => round.roundWon).length,
roundsSubmitted: historicalRounds.filter(round => round.bestDLSubmitted).length,
roundsWithDLs: historicalRounds.filter(round => round.bestDL).length,
totalRounds: historicalRounds.length,
historicalRounds,
};
}
async getHistoricalRounds() {
const rounds = await database().round.findAll({
where: {
upstream: this.fullUpstreamName,
},
order: [
['blockHeight', 'ASC'],
],
});
return rounds.map(round => {
const roundJSON = round.toJSON();
roundJSON.netDiff = coinUtil.modifyNetDiff(roundJSON.netDiff, this.upstreamConfig.coin);
if (roundJSON.bestDL !== null) {
roundJSON.bestDL = coinUtil.modifyDeadline(parseInt(roundJSON.bestDL, 10), this.upstreamConfig.coin);
}
if (roundJSON.bestDLSubmitted !== null) {
roundJSON.bestDLSubmitted = coinUtil.modifyDeadline(parseInt(roundJSON.bestDLSubmitted, 10), this.upstreamConfig.coin);
}
return roundJSON;
});
}
async getStats() {
const upstreamStats = {
name: this.upstreamConfig.name,
color: this.upstreamConfig.color,
fullName: this.fullUpstreamName,
isBHD: this.isBHD || !!this.upstreamConfig.isBHD,
coin: this.upstreamConfig.coin,
url: this.upstreamConfig.url,
isFoxyPool: this.upstreamConfig.type === 'foxypool',
};
const connectionStats = this.getConnectionStats();
const currentRoundStats = this.getCurrentRoundStats();
const historicalStats = await this.getHistoricalStats();
return {
...upstreamStats,
...connectionStats,
...currentRoundStats,
...historicalStats,
};
}
getTotalCapacity() {
if (this.upstreamConfig.capacity !== undefined) {
return parseInt(this.upstreamConfig.capacity, 10);
}
return util.getTotalMinerCapacity(this.miners);
}
recalculateTotalCapacity() {
this.totalCapacity = this.getTotalCapacity();
}
async createOrUpdateRound({ miningInfo }) {
if (!miningInfo || !miningInfo.height) {
return;
}
await cache.createOrUpdateRound({
upstream: this.fullUpstreamName,
blockHeight: miningInfo.height,
baseTarget: miningInfo.baseTarget,
netDiff: miningInfo.netDiff,
});
}
async onRoundEnded({ oldMiningInfo }) {
if (!oldMiningInfo || !oldMiningInfo.height) {
return;
}
if (this.canFetchBlockInfo()) {
await new Promise(resolve => setTimeout(resolve, 10 * 1000));
await roundPopulator.populateUnpopulatedRounds(this, oldMiningInfo.height);
}
await cache.removeOldCachedRounds(this, oldMiningInfo.height);
await cache.removeOldRounds({
upstream: this.fullUpstreamName,
roundsToKeep: this.upstreamConfig.historicalRoundsToKeep || 720,
});
}
async getActivePlotter(height) {
return database().plotter.findAll({
where: {
upstream: this.fullUpstreamName,
lastSubmitHeight: {
[database().Op.gte]: height - 100,
},
},
});
}
get walletUrl() {
let walletUrl = this.upstreamConfig.walletUrl;
if (!walletUrl && this.upstreamConfig.mode === 'solo') {
walletUrl = this.upstreamConfig.url;
}
if (!walletUrl && this.hostedWalletUrl) {
walletUrl = this.hostedWalletUrl;
}
return walletUrl;
}
get hostedWalletUrl() {
switch (this.upstreamConfig.coin) {
case 'BHD': return 'https://bhd.wallet.foxypool.io';
case 'BURST': return 'https://burst.wallet.foxypool.io';
default: return null;
}
}
canFetchBlockInfo() {
return !!(this.walletUrl && this.upstreamConfig.coin);
}
getBlockInfo(height) {
if (!this.canFetchBlockInfo()) {
return null;
}
switch (this.upstreamConfig.coin) {
case 'LHD':
case 'HDD':
case 'XHD':
case 'DISC':
case 'BHD': return util.getBhdBlockInfo({ url: this.walletUrl, height });
case 'BURST': return util.getBurstBlockInfo({ url: this.walletUrl, height });
default: return null;
}
}
};