Add out of band fees to pools page

This commit is contained in:
Mononaut 2024-03-15 07:41:07 +00:00
parent 120ffdb0f4
commit a44219a3c3
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
4 changed files with 88 additions and 2 deletions

View File

@ -39,6 +39,7 @@ class MiningRoutes {
.get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/pool/:slug', this.$getAccelerationsByPool) .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/pool/:slug', this.$getAccelerationsByPool)
.get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/block/:height', this.$getAccelerationsByHeight) .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/block/:height', this.$getAccelerationsByHeight)
.get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/recent/:interval', this.$getRecentAccelerations) .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/recent/:interval', this.$getRecentAccelerations)
.get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/total', this.$getAccelerationTotals)
; ;
} }
@ -403,6 +404,21 @@ class MiningRoutes {
res.status(500).send(e instanceof Error ? e.message : e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
private async $getAccelerationTotals(req: Request, res: Response): Promise<void> {
try {
res.header('Pragma', 'public');
res.header('Cache-control', 'public');
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) {
res.status(400).send('Acceleration data is not available.');
return;
}
res.status(200).send(await AccelerationRepository.$getAccelerationTotals(<string>req.query.pool, <string>req.query.interval));
} catch (e) {
res.status(500).send(e instanceof Error ? e.message : e);
}
}
} }
export default new MiningRoutes(); export default new MiningRoutes();

View File

@ -118,6 +118,45 @@ class AccelerationRepository {
} }
} }
public async $getAccelerationTotals(poolSlug: string | null = null, interval: string | null = null): Promise<{ cost: number, count: number }> {
interval = Common.getSqlInterval(interval);
if (!config.MEMPOOL_SERVICES.ACCELERATIONS) {
return { cost: 0, count: 0 };
}
let query = `
SELECT SUM(boost_cost) as total_cost, COUNT(txid) as count FROM accelerations
JOIN pools on pools.unique_id = accelerations.pool
`;
let params: any[] = [];
let hasFilter = false;
if (interval) {
query += ` WHERE accelerations.added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() `;
hasFilter = true;
}
if (poolSlug != null) {
if (hasFilter) {
query += ` AND pools.slug = ? `;
} else {
query += ` WHERE pools.slug = ? `;
}
params.push(poolSlug);
}
try {
const [rows] = await DB.query(query, params) as RowDataPacket[][];
return {
cost: rows[0]?.total_cost || 0,
count: rows[0]?.count || 0,
};
} catch (e) {
logger.err(`Cannot query acceleration totals. Reason: ` + (e instanceof Error ? e.message : e));
throw e;
}
}
public async $getLastSyncedHeight(): Promise<number> { public async $getLastSyncedHeight(): Promise<number> {
try { try {
const [rows] = await DB.query(` const [rows] = await DB.query(`

View File

@ -1,8 +1,8 @@
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { echarts, EChartsOption } from '../../graphs/echarts'; import { echarts, EChartsOption } from '../../graphs/echarts';
import { BehaviorSubject, Observable, of, timer } from 'rxjs'; import { BehaviorSubject, Observable, combineLatest, of, timer } from 'rxjs';
import { catchError, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; import { catchError, distinctUntilChanged, filter, map, share, switchMap, tap } from 'rxjs/operators';
import { BlockExtended, PoolStat } from '../../interfaces/node-api.interface'; import { BlockExtended, PoolStat } from '../../interfaces/node-api.interface';
import { ApiService } from '../../services/api.service'; import { ApiService } from '../../services/api.service';
import { StateService } from '../../services/state.service'; import { StateService } from '../../services/state.service';
@ -10,6 +10,11 @@ import { selectPowerOfTen } from '../../bitcoin.utils';
import { formatNumber } from '@angular/common'; import { formatNumber } from '@angular/common';
import { SeoService } from '../../services/seo.service'; import { SeoService } from '../../services/seo.service';
interface AccelerationTotal {
cost: number,
count: number,
}
@Component({ @Component({
selector: 'app-pool', selector: 'app-pool',
templateUrl: './pool.component.html', templateUrl: './pool.component.html',
@ -25,6 +30,7 @@ export class PoolComponent implements OnInit {
formatNumber = formatNumber; formatNumber = formatNumber;
poolStats$: Observable<PoolStat>; poolStats$: Observable<PoolStat>;
blocks$: Observable<BlockExtended[]>; blocks$: Observable<BlockExtended[]>;
oobFees$: Observable<AccelerationTotal[]>;
isLoading = true; isLoading = true;
chartOptions: EChartsOption = {}; chartOptions: EChartsOption = {};
@ -111,6 +117,17 @@ export class PoolComponent implements OnInit {
map(() => this.blocks), map(() => this.blocks),
share(), share(),
); );
this.oobFees$ = this.route.params.pipe(map((params) => params.slug)).pipe(
switchMap(slug => {
return combineLatest([
this.apiService.getAccelerationTotals$(this.slug, '1w'),
this.apiService.getAccelerationTotals$(this.slug, '1m'),
this.apiService.getAccelerationTotals$(this.slug),
]);
}),
filter(oob => oob.length === 3 && oob[2].count > 0)
);
} }
prepareChartOptions(data) { prepareChartOptions(data) {

View File

@ -442,4 +442,18 @@ export class ApiService {
this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/interval' + (interval !== undefined ? `/${interval}` : '') this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/interval' + (interval !== undefined ? `/${interval}` : '')
); );
} }
getAccelerationTotals$(pool?: string, interval?: string): Observable<{ cost: number, count: number }> {
const queryParams = new URLSearchParams();
if (pool) {
queryParams.append('pool', pool);
}
if (interval) {
queryParams.append('interval', interval);
}
const queryString = queryParams.toString();
return this.httpClient.get<{ cost: number, count: number }>(
this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/total' + (queryString?.length ? '?' + queryString : '')
);
}
} }