From 382152132df921196f31fae7f699dea09a372d2d Mon Sep 17 00:00:00 2001 From: Branko Bosnic Date: Fri, 8 Mar 2024 10:12:44 +0100 Subject: [PATCH] fix: add chart for daily transactions --- api/src/models/influx/nova/IInfluxDbCache.ts | 4 +++- .../models/influx/nova/IInfluxTimedEntries.ts | 5 +++++ .../routes/nova/analytics/influx/daily/get.ts | 4 +++- api/src/services/nova/influx/influxQueries.ts | 19 +++++++++++++++++++ .../services/nova/influx/influxServiceNova.ts | 9 +++++++-- .../nova/statistics/InfluxChartsTab.tsx | 11 ++++++++++- .../src/helpers/nova/hooks/useChartsState.ts | 9 +++++++-- client/src/helpers/nova/statisticsUtils.ts | 7 +++++++ .../api/nova/influx/IInfluxDailyResponse.ts | 7 +++++++ 9 files changed, 68 insertions(+), 7 deletions(-) diff --git a/api/src/models/influx/nova/IInfluxDbCache.ts b/api/src/models/influx/nova/IInfluxDbCache.ts index 8379553b9..0ef07f074 100644 --- a/api/src/models/influx/nova/IInfluxDbCache.ts +++ b/api/src/models/influx/nova/IInfluxDbCache.ts @@ -1,4 +1,4 @@ -import { IBlocksDailyInflux } from "./IInfluxTimedEntries"; +import { IBlocksDailyInflux, ITransactionsDailyInflux } from "./IInfluxTimedEntries"; import { DayKey } from "../types"; /** @@ -6,6 +6,7 @@ import { DayKey } from "../types"; */ export interface IInfluxDailyCache { blocksDaily: Map; + transactionsDaily: Map; } /** @@ -14,4 +15,5 @@ export interface IInfluxDailyCache { */ export const initializeEmptyDailyCache = () => ({ blocksDaily: new Map(), + transactionsDaily: new Map(), }); diff --git a/api/src/models/influx/nova/IInfluxTimedEntries.ts b/api/src/models/influx/nova/IInfluxTimedEntries.ts index 9ced5f9b4..090d5c09c 100644 --- a/api/src/models/influx/nova/IInfluxTimedEntries.ts +++ b/api/src/models/influx/nova/IInfluxTimedEntries.ts @@ -6,3 +6,8 @@ export type IBlocksDailyInflux = ITimedEntry & { validation: number | null; candidacy: number | null; }; + +export type ITransactionsDailyInflux = ITimedEntry & { + finalized: number | null; + failed: number | null; +}; diff --git a/api/src/routes/nova/analytics/influx/daily/get.ts b/api/src/routes/nova/analytics/influx/daily/get.ts index 6aa3551bc..8b77a8f29 100644 --- a/api/src/routes/nova/analytics/influx/daily/get.ts +++ b/api/src/routes/nova/analytics/influx/daily/get.ts @@ -2,7 +2,7 @@ import { ServiceFactory } from "../../../../../factories/serviceFactory"; import { INetworkBoundGetRequest } from "../../../../../models/api/INetworkBoundGetRequest"; import { IConfiguration } from "../../../../../models/configuration/IConfiguration"; import { NOVA } from "../../../../../models/db/protocolVersion"; -import { IBlocksDailyInflux } from "../../../../../models/influx/nova/IInfluxTimedEntries"; +import { IBlocksDailyInflux, ITransactionsDailyInflux } from "../../../../../models/influx/nova/IInfluxTimedEntries"; import { NetworkService } from "../../../../../services/networkService"; import { InfluxServiceNova } from "../../../../../services/nova/influx/influxServiceNova"; import { ValidationHelper } from "../../../../../utils/validationHelper"; @@ -13,6 +13,7 @@ import { ValidationHelper } from "../../../../../utils/validationHelper"; export interface IDailyAnalyticsResponse { error?: string; blocksDaily?: IBlocksDailyInflux[]; + transactionsDaily?: ITransactionsDailyInflux[]; } /** @@ -36,6 +37,7 @@ export async function get(_: IConfiguration, request: INetworkBoundGetRequest): return influxService ? { blocksDaily: influxService.blocksDaily, + transactionsDaily: influxService.transactionsDaily, } : { error: "Influx service not found for this network.", diff --git a/api/src/services/nova/influx/influxQueries.ts b/api/src/services/nova/influx/influxQueries.ts index 0547d2385..0863bd309 100644 --- a/api/src/services/nova/influx/influxQueries.ts +++ b/api/src/services/nova/influx/influxQueries.ts @@ -20,3 +20,22 @@ export const BLOCK_DAILY_QUERY = { GROUP BY time(1d) fill(null) `, }; + +export const TRANSACTION_DAILY_QUERY = { + full: ` + SELECT + sum("finalized_count") AS "finalized", + sum("failed_count") AS "failed" + FROM "iota_block_activity" + WHERE time < $to + GROUP BY time(1d) fill(null) + `, + partial: ` + SELECT + sum("finalized_count") AS "finalized", + sum("failed_count") AS "failed" + FROM "iota_block_activity" + WHERE time >= $from and time <= $to + GROUP BY time(1d) fill(null) + `, +}; diff --git a/api/src/services/nova/influx/influxServiceNova.ts b/api/src/services/nova/influx/influxServiceNova.ts index 6a36c84dc..a59406f92 100644 --- a/api/src/services/nova/influx/influxServiceNova.ts +++ b/api/src/services/nova/influx/influxServiceNova.ts @@ -1,9 +1,9 @@ import { InfluxDB } from "influx"; -import { BLOCK_DAILY_QUERY } from "./influxQueries"; +import { BLOCK_DAILY_QUERY, TRANSACTION_DAILY_QUERY } from "./influxQueries"; import logger from "../../../logger"; import { INetwork } from "../../../models/db/INetwork"; import { IInfluxDailyCache, initializeEmptyDailyCache } from "../../../models/influx/nova/IInfluxDbCache"; -import { IBlocksDailyInflux } from "../../../models/influx/nova/IInfluxTimedEntries"; +import { IBlocksDailyInflux, ITransactionsDailyInflux } from "../../../models/influx/nova/IInfluxTimedEntries"; import { InfluxDbClient } from "../../influx/influxClient"; export class InfluxServiceNova extends InfluxDbClient { @@ -31,6 +31,10 @@ export class InfluxServiceNova extends InfluxDbClient { return this.mapToSortedValuesArray(this._dailyCache.blocksDaily); } + public get transactionsDaily() { + return this.mapToSortedValuesArray(this._dailyCache.transactionsDaily); + } + protected setupDataCollection() { const network = this._network.network; logger.verbose(`[InfluxNova] Setting up data collection for (${network}).`); @@ -46,5 +50,6 @@ export class InfluxServiceNova extends InfluxDbClient { private async collectGraphsDaily() { logger.verbose(`[InfluxNova] Collecting daily stats for "${this._network.network}"`); this.updateCacheEntry(BLOCK_DAILY_QUERY, this._dailyCache.blocksDaily, "Blocks Daily", true); + this.updateCacheEntry(TRANSACTION_DAILY_QUERY, this._dailyCache.transactionsDaily, "Transactions Daily"); } } diff --git a/client/src/app/components/nova/statistics/InfluxChartsTab.tsx b/client/src/app/components/nova/statistics/InfluxChartsTab.tsx index 7f0620d45..22fa6df79 100644 --- a/client/src/app/components/nova/statistics/InfluxChartsTab.tsx +++ b/client/src/app/components/nova/statistics/InfluxChartsTab.tsx @@ -6,7 +6,7 @@ import Modal from "../../Modal"; import StackedLineChart from "../../stardust/statistics/charts/StackedLineChart"; export const InfluxChartsTab: React.FC = () => { - const { dailyBlocks } = useChartsState(); + const { dailyBlocks, dailyTransactions } = useChartsState(); const ids = idGenerator(); @@ -27,6 +27,15 @@ export const InfluxChartsTab: React.FC = () => { colors={["#4140DF", "#14CABF", "#36A1AC", "#99BEE1"]} data={dailyBlocks} /> + diff --git a/client/src/helpers/nova/hooks/useChartsState.ts b/client/src/helpers/nova/hooks/useChartsState.ts index c831ec412..33b32f959 100644 --- a/client/src/helpers/nova/hooks/useChartsState.ts +++ b/client/src/helpers/nova/hooks/useChartsState.ts @@ -9,10 +9,14 @@ import { DataPoint, IStatisticsGraphsData, mapDailyStatsToGraphsData } from "../ * State holder for Statistics page chart section. * @returns The charts state. */ -export function useChartsState(): { dailyBlocks: DataPoint[] } { +export function useChartsState(): { + dailyBlocks: DataPoint[]; + dailyTransactions: DataPoint[]; +} { const { name: network } = useNetworkInfoNova((s) => s.networkInfo); const [apiClient] = useState(ServiceFactory.get(`api-client-${NOVA}`)); const [dailyBlocks, setDailyBlocks] = useState([]); + const [dailyTransactions, setDailyTransactions] = useState([]); useEffect(() => { apiClient @@ -22,6 +26,7 @@ export function useChartsState(): { dailyBlocks: DataPoint[] } { const graphsData: IStatisticsGraphsData = mapDailyStatsToGraphsData(influxStats); setDailyBlocks(graphsData.blocksDaily); + setDailyTransactions(graphsData.transactionsDaily); } else { console.error("Fetching influx stats failed", influxStats.error); } @@ -29,5 +34,5 @@ export function useChartsState(): { dailyBlocks: DataPoint[] } { .catch((e) => console.error("Influx analytics fetch failed", e)); }, [network]); - return { dailyBlocks }; + return { dailyBlocks, dailyTransactions }; } diff --git a/client/src/helpers/nova/statisticsUtils.ts b/client/src/helpers/nova/statisticsUtils.ts index 493feb2ae..50bbe0db5 100644 --- a/client/src/helpers/nova/statisticsUtils.ts +++ b/client/src/helpers/nova/statisticsUtils.ts @@ -3,6 +3,7 @@ import { IInfluxDailyResponse } from "~models/api/nova/influx/IInfluxDailyRespon export interface IStatisticsGraphsData { blocksDaily: DataPoint[]; + transactionsDaily: DataPoint[]; } export interface DataPoint { @@ -25,6 +26,12 @@ export function mapDailyStatsToGraphsData(data: IInfluxDailyResponse): IStatisti validation: day.validation ?? 0, candidacy: day.candidacy ?? 0, })) ?? [], + transactionsDaily: + data.transactionsDaily?.map((t) => ({ + time: moment(t.time).add(1, "minute").unix(), + finalized: t.finalized ?? 0, + failed: t.failed ?? 0, + })) ?? [], }; } diff --git a/client/src/models/api/nova/influx/IInfluxDailyResponse.ts b/client/src/models/api/nova/influx/IInfluxDailyResponse.ts index 41ecdf919..c824267f3 100644 --- a/client/src/models/api/nova/influx/IInfluxDailyResponse.ts +++ b/client/src/models/api/nova/influx/IInfluxDailyResponse.ts @@ -8,6 +8,13 @@ interface IBlocksDailyInflux { candidacy: number | null; } +interface ITransactionsDailyInflux { + time: Date; + finalized: number | null; + failed: number | null; +} + export interface IInfluxDailyResponse extends IResponse { blocksDaily?: IBlocksDailyInflux[]; + transactionsDaily?: ITransactionsDailyInflux[]; }