network stats and better client hashrate estimation

This commit is contained in:
Ben Wilson
2023-08-03 22:37:48 -04:00
parent 3c4c35ab53
commit f907d6efe1
4 changed files with 31 additions and 19 deletions
@@ -188,8 +188,7 @@ export class ClientStatisticsService {
WHERE WHERE
entry.address = ? AND entry.clientName = ? AND entry.sessionId = ? entry.address = ? AND entry.clientName = ? AND entry.sessionId = ?
ORDER BY time DESC ORDER BY time DESC
LIMIT 1; LIMIT 2;
`; `;
const result = await this.clientStatisticsRepository.query(query, [address, clientName, sessionId]); const result = await this.clientStatisticsRepository.query(query, [address, clientName, sessionId]);
@@ -198,13 +197,22 @@ export class ClientStatisticsService {
return 0; return 0;
} }
const time = new Date(result[0].updatedAt).getTime() - new Date(result[0].createdAt).getTime(); const latestStat = result[0];
if (result.length < 2) {
const time = new Date(latestStat.updatedAt).getTime() - new Date(latestStat.createdAt).getTime();
if (time < 1) { if (time < 1) {
return 0; return 0;
} }
return (latestStat.shares * 4294967296) / (time / 1000);
return (result[0].shares * 4294967296) / (time / 1000); } else {
const secondLatestStat = result[1];
const time = new Date(latestStat.updatedAt).getTime() - new Date(secondLatestStat.createdAt).getTime();
if (time < 1) {
return 0;
}
return ((latestStat.shares + secondLatestStat.shares) * 4294967296) / (time / 1000);
}
} }
+14 -4
View File
@@ -1,18 +1,21 @@
import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Controller, Get, Inject } from '@nestjs/common'; import { Controller, Get, Inject } from '@nestjs/common';
import { Cache } from 'cache-manager'; import { Cache } from 'cache-manager';
import { firstValueFrom } from 'rxjs';
import { BlocksService } from './ORM/blocks/blocks.service'; import { BlocksService } from './ORM/blocks/blocks.service';
import { ClientStatisticsService } from './ORM/client-statistics/client-statistics.service'; import { ClientStatisticsService } from './ORM/client-statistics/client-statistics.service';
import { ClientService } from './ORM/client/client.service'; import { ClientService } from './ORM/client/client.service';
import { BitcoinRpcService } from './services/bitcoin-rpc.service';
@Controller() @Controller()
export class AppController { export class AppController {
constructor( constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache, @Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
private clientService: ClientService, private readonly clientService: ClientService,
private clientStatisticsService: ClientStatisticsService, private readonly clientStatisticsService: ClientStatisticsService,
private blocksService: BlocksService private readonly blocksService: BlocksService,
private readonly bitcoinRpcService: BitcoinRpcService
) { } ) { }
@Get('info') @Get('info')
@@ -26,6 +29,13 @@ export class AppController {
userAgents userAgents
}; };
} }
@Get('network')
public async network() {
const miningInfo = await firstValueFrom(this.bitcoinRpcService.newBlock$);
return miningInfo;
}
@Get('info/chart') @Get('info/chart')
public async infoChart() { public async infoChart() {
+2 -2
View File
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { RPCClient } from 'rpc-bitcoin'; import { RPCClient } from 'rpc-bitcoin';
import { BehaviorSubject, filter } from 'rxjs'; import { BehaviorSubject, filter, shareReplay } from 'rxjs';
import { IBlockTemplate } from '../models/bitcoin-rpc/IBlockTemplate'; import { IBlockTemplate } from '../models/bitcoin-rpc/IBlockTemplate';
import { IMiningInfo } from '../models/bitcoin-rpc/IMiningInfo'; import { IMiningInfo } from '../models/bitcoin-rpc/IMiningInfo';
@@ -12,7 +12,7 @@ export class BitcoinRpcService {
private blockHeight = 0; private blockHeight = 0;
private client: RPCClient; private client: RPCClient;
private _newBlock$: BehaviorSubject<IMiningInfo> = new BehaviorSubject(undefined); private _newBlock$: BehaviorSubject<IMiningInfo> = new BehaviorSubject(undefined);
public newBlock$ = this._newBlock$.pipe(filter(block => block != null)); public newBlock$ = this._newBlock$.pipe(filter(block => block != null), shareReplay({ refCount: true, bufferSize: 1 }));
constructor(private readonly configService: ConfigService) { constructor(private readonly configService: ConfigService) {
const url = this.configService.get('BITCOIN_RPC_URL'); const url = this.configService.get('BITCOIN_RPC_URL');
-6
View File
@@ -4,7 +4,6 @@ import * as merkle from 'merkle-lib';
import * as merkleProof from 'merkle-lib/proof'; import * as merkleProof from 'merkle-lib/proof';
import { combineLatest, filter, from, interval, map, Observable, shareReplay, startWith, switchMap, tap } from 'rxjs'; import { combineLatest, filter, from, interval, map, Observable, shareReplay, startWith, switchMap, tap } from 'rxjs';
import { IBlockTemplate } from '../models/bitcoin-rpc/IBlockTemplate';
import { MiningJob } from '../models/MiningJob'; import { MiningJob } from '../models/MiningJob';
import { BitcoinRpcService } from './bitcoin-rpc.service'; import { BitcoinRpcService } from './bitcoin-rpc.service';
@@ -36,13 +35,10 @@ export class StratumV1JobsService {
public blocks: { [id: number]: IJobTemplate } = {}; public blocks: { [id: number]: IJobTemplate } = {};
private currentBlockTemplate$: Observable<{ blockTemplate: IBlockTemplate }>;
constructor( constructor(
private readonly bitcoinRpcService: BitcoinRpcService private readonly bitcoinRpcService: BitcoinRpcService
) { ) {
this.newMiningJob$ = combineLatest([this.bitcoinRpcService.newBlock$, interval(60000).pipe(startWith(-1))]).pipe( this.newMiningJob$ = combineLatest([this.bitcoinRpcService.newBlock$, interval(60000).pipe(startWith(-1))]).pipe(
switchMap(([miningInfo, interval]) => { switchMap(([miningInfo, interval]) => {
return from(this.bitcoinRpcService.getBlockTemplate()).pipe(map((blockTemplate) => { return from(this.bitcoinRpcService.getBlockTemplate()).pipe(map((blockTemplate) => {
@@ -102,8 +98,6 @@ export class StratumV1JobsService {
// remove the first (coinbase) and last (root) element from the branch // remove the first (coinbase) and last (root) element from the branch
const merkle_branch = merkleBranches.slice(1, merkleBranches.length).map(b => b.toString('hex')) const merkle_branch = merkleBranches.slice(1, merkleBranches.length).map(b => b.toString('hex'))
block.prevHash = prevHash; block.prevHash = prevHash;
block.version = version; block.version = version;
block.bits = bits; block.bits = bits;