diff --git a/src/containers/navigation/components/MiningTiles/CPU.tsx b/src/containers/navigation/components/MiningTiles/CPU.tsx index a84725812..6fe5159de 100644 --- a/src/containers/navigation/components/MiningTiles/CPU.tsx +++ b/src/containers/navigation/components/MiningTiles/CPU.tsx @@ -39,6 +39,7 @@ export default function CPUTile() { progressDiff={rewardsRef.current?.rewardValue} unpaidFMT={rewardsRef.current?.unpaidFMT || '-'} minerModuleState={cpuMiningModuleState} + hashRateUnit="H" /> ); } diff --git a/src/containers/navigation/components/MiningTiles/GPU.tsx b/src/containers/navigation/components/MiningTiles/GPU.tsx index 5e757489d..456fb9800 100644 --- a/src/containers/navigation/components/MiningTiles/GPU.tsx +++ b/src/containers/navigation/components/MiningTiles/GPU.tsx @@ -4,7 +4,6 @@ import { useMiningPoolsStore } from '@app/store/useMiningPoolsStore'; import { useEffect, useRef } from 'react'; import { setupStoreSelectors } from '@app/store/selectors/setupStoreSelectors'; import { useSetupStore } from '@app/store/useSetupStore'; -import { getSelectedMiner } from '@app/store/selectors/minningStoreSelectors'; export default function GPUTile() { const gpuPoolStats = useMiningPoolsStore((s) => s.gpuPoolStats); @@ -17,7 +16,6 @@ export default function GPUTile() { const miningInitiated = useMiningStore((s) => s.isGpuMiningInitiated); const gpu_mining_status = useMiningMetricsStore((s) => s.gpu_mining_status); const isGpuPoolEnabled = useConfigPoolsStore((s) => s.gpu_pool_enabled); - const selectedMiner = useMiningStore(getSelectedMiner); const { hash_rate, is_mining } = gpu_mining_status; useEffect(() => useMiningPoolsStore.subscribe((s) => (statsRef.current = s.gpuPoolStats)), []); @@ -40,7 +38,6 @@ export default function GPUTile() { progressDiff={rewardsRef.current?.rewardValue} unpaidFMT={rewardsRef.current?.unpaidFMT || '-'} minerModuleState={gpuMiningModuleState} - algo={selectedMiner?.supported_algorithms?.[0]} /> ); } diff --git a/src/containers/navigation/components/MiningTiles/Miner.tsx b/src/containers/navigation/components/MiningTiles/Miner.tsx index ea49703e9..bc626f551 100644 --- a/src/containers/navigation/components/MiningTiles/Miner.tsx +++ b/src/containers/navigation/components/MiningTiles/Miner.tsx @@ -1,5 +1,5 @@ import { PoolStats } from '@app/types/app-status'; -import { formatHashrate, formatNumber, FormatPreset } from '@app/utils'; +import { formatHashrate, formatNumber, FormatPreset, type HashrateUnit } from '@app/utils'; import { Trans, useTranslation } from 'react-i18next'; import Tile from './components/Tile/Tile'; import { AnimatePresence } from 'motion/react'; @@ -16,7 +16,6 @@ import { offset, useFloating, useHover, useInteractions } from '@floating-ui/rea import { useState } from 'react'; import { PoolType } from '@app/store/useMiningPoolsStore.ts'; import { AppModuleState, AppModuleStatus } from '@app/store/types/setup.ts'; -import { GpuMiningAlgorithm } from '@app/types/events-payloads.ts'; export interface MinerTileProps { title: PoolType; mainLabelKey: string; @@ -31,7 +30,7 @@ export interface MinerTileProps { progressDiff?: number | null; unpaidFMT?: string; minerModuleState: AppModuleState; - algo?: GpuMiningAlgorithm; + hashRateUnit?: HashrateUnit; } export default function MinerTile({ @@ -48,7 +47,7 @@ export default function MinerTile({ progressDiff, unpaidFMT, minerModuleState, - algo = GpuMiningAlgorithm.C29, + hashRateUnit = 'G', }: MinerTileProps) { const { t } = useTranslation(['mining-view', 'p2p'], { useSuspense: false }); @@ -57,7 +56,7 @@ export default function MinerTile({ const hashrateLoading = enabled && isMining && hashRate <= 0; const isLoading = (isMiningInitiated && !isMining) || (isMining && !isMiningInitiated) || hashrateLoading; - const formattedHashRate = formatHashrate(hashRate, true, algo); + const formattedHashRate = formatHashrate(hashRate, true, hashRateUnit); const currentUnpaid = (poolStats?.unpaid || 0) / 1_000_000; const mainNumber = isPoolEnabled ? currentUnpaid : formattedHashRate.value; diff --git a/src/utils/formatters.test.ts b/src/utils/formatters.test.ts index 3dd7d0f89..aa43fdb35 100644 --- a/src/utils/formatters.test.ts +++ b/src/utils/formatters.test.ts @@ -195,27 +195,27 @@ describe('formatters', () => { it('formats hashrates >= 1000 with kG/s', () => { const result = formatHashrate(1500); - expect(result).toEqual({ value: 1.5, unit: ' kG/s' }); + expect(result).toEqual({ value: 1.5, unit: 'kG/s' }); }); it('formats hashrates >= 1000000 with MG/s', () => { const result = formatHashrate(1_500_000); - expect(result).toEqual({ value: 1.5, unit: ' MG/s' }); + expect(result).toEqual({ value: 1.5, unit: 'MG/s' }); }); it('formats hashrates >= 1000000000 with GG/s', () => { const result = formatHashrate(1_500_000_000); - expect(result).toEqual({ value: 1.5, unit: ' GG/s' }); + expect(result).toEqual({ value: 1.5, unit: 'GG/s' }); }); it('formats hashrates >= 1000000000000 with TG/s', () => { const result = formatHashrate(1_500_000_000_000); - expect(result).toEqual({ value: 1.5, unit: ' TG/s' }); + expect(result).toEqual({ value: 1.5, unit: 'TG/s' }); }); it('formats hashrates >= 1000000000000000 with PG/s', () => { const result = formatHashrate(1_500_000_000_000_000); - expect(result).toEqual({ value: 1.5, unit: ' PG/s' }); + expect(result).toEqual({ value: 1.5, unit: 'PG/s' }); }); it('returns short unit when joinUnit is false', () => { @@ -225,7 +225,7 @@ describe('formatters', () => { it('handles edge case at exactly 1000', () => { const result = formatHashrate(1000); - expect(result).toEqual({ value: 1, unit: ' kG/s' }); + expect(result).toEqual({ value: 1, unit: 'kG/s' }); }); it('handles zero hashrate', () => { @@ -233,6 +233,17 @@ describe('formatters', () => { expect(result).toEqual({ value: 0, unit: 'G/s' }); }); + it('formats CPU RandomX hashrates with H/s units', () => { + expect(formatHashrate(500, true, 'H')).toEqual({ value: 500, unit: 'H/s' }); + expect(formatHashrate(1500, true, 'H')).toEqual({ value: 1.5, unit: 'kH/s' }); + expect(formatHashrate(1_500_000, true, 'H')).toEqual({ value: 1.5, unit: 'MH/s' }); + }); + + it('respects joinUnit for hashrates under 1000', () => { + const result = formatHashrate(500, false); + expect(result).toEqual({ value: 500, unit: '' }); + }); + it('rounds large values to 1 decimal', () => { const result = formatHashrate(150); expect(result).toEqual({ value: 150, unit: 'G/s' }); diff --git a/src/utils/formatters.ts b/src/utils/formatters.ts index adde1fde4..86d1c6710 100644 --- a/src/utils/formatters.ts +++ b/src/utils/formatters.ts @@ -1,4 +1,3 @@ -import { GpuMiningAlgorithm } from '@app/types/events-payloads'; import i18n from 'i18next'; import { TimeParts } from '@app/types/mining/schedule.ts'; @@ -126,42 +125,44 @@ interface Hashrate { unit: string; } -export function formatHashrate(hashrate: number, joinUnit = true, _algo = GpuMiningAlgorithm.C29): Hashrate { - const unit = 'G'; +export type HashrateUnit = 'H' | 'G'; + +export function formatHashrate(hashrate: number, joinUnit = true, unit: HashrateUnit = 'G'): Hashrate { const fixed = (val: number, dec = 2) => Number(val.toFixed(val >= 100 ? 1 : dec)); + const formatUnit = (prefix = '') => (joinUnit ? `${prefix}${unit}/s` : prefix); if (hashrate < 1000) { return { value: fixed(hashrate, 1), - unit: `${unit}/s`, + unit: formatUnit(), }; } if (hashrate < 1000000) { return { value: fixed(hashrate / 1000), - unit: joinUnit ? ` k${unit}/s` : 'k', + unit: formatUnit('k'), }; } if (hashrate < 1000000000) { return { value: fixed(hashrate / 1000000), - unit: joinUnit ? ` M${unit}/s` : 'M', + unit: formatUnit('M'), }; } if (hashrate < 1000000000000) { return { value: fixed(hashrate / 1000000000), - unit: joinUnit ? ` G${unit}/s` : 'G', + unit: formatUnit('G'), }; } if (hashrate < 1000000000000000) { return { value: fixed(hashrate / 1000000000000), - unit: joinUnit ? ` T${unit}/s` : 'T', + unit: formatUnit('T'), }; } else { return { value: fixed(hashrate / 1000000000000000), - unit: joinUnit ? ` P${unit}/s` : 'P', + unit: formatUnit('P'), }; } }