fix(proposals): parsing block duration value (#4613)

This commit is contained in:
Art 2023-08-28 15:11:24 +02:00 committed by GitHub
parent 3422b99491
commit 0fb8ee3abb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 3 deletions

View File

@ -1,5 +1,9 @@
import { renderHook, waitFor } from '@testing-library/react';
import { useTimeToUpgrade } from './use-time-to-upgrade';
import {
ERR_NO_TIME_UNITS,
parseDuration,
useTimeToUpgrade,
} from './use-time-to-upgrade';
jest.mock('./__generated__/BlockStatistics', () => ({
...jest.requireActual('./__generated__/BlockStatistics'),
@ -8,7 +12,7 @@ jest.mock('./__generated__/BlockStatistics', () => ({
data: {
statistics: {
blockHeight: 1,
blockDuration: 500,
blockDuration: '500ms',
},
},
};
@ -30,3 +34,25 @@ describe('useTimeToUpgrade', () => {
});
});
});
describe('parseDuration', () => {
it.each([
['1000000ns', 1],
['1000µs', 1],
['1ms', 1],
['1s', 1000],
['1m', 60 * 1000],
['1h', 60 * 60 * 1000],
// below test cases are from vega
['3.3s', 3300],
['4m5s', 4 * 60 * 1000 + 5 * 1000],
['4m5.001s', 4 * 60 * 1000 + 5001],
['5h6m7.001s', 5 * 60 * 60 * 1000 + 6 * 60 * 1000 + 7001],
['8m0.000000001s', 8 * 60 * 1000 + 1 / 1000000],
])('parses %s to %d milliseconds', (input, output) => {
expect(parseDuration(input)).toEqual(output);
});
it('throws an error when given corrupted data', () => {
expect(() => parseDuration('blah')).toThrow(ERR_NO_TIME_UNITS);
});
});

View File

@ -7,6 +7,52 @@ const DEFAULT_POLLS = 10;
const INTERVAL = 1000;
const durations = [] as number[];
export const ERR_NO_TIME_UNITS = new Error(
'could not parse block duration value - no time units detected'
);
/**
* Parses block duration value and output a number of milliseconds.
* @param input The block duration input from the API, e.g. 4m5.001s
* @returns A number of milliseconds
*/
export const parseDuration = (input: string) => {
// h -> 60*60*1000
// m -> 60*1000
// s -> 1000
// ms -> 1
// µs -> 1/1000
// ns -> 1/1000000
let H = 0;
let M = 0;
let S = 0;
const lessThanSecond = /^[0-9.]+[nµm]*s$/gu.test(input);
const exp = /(?<hours>[0-9.]+h)?(?<minutes>[0-9.]+m)?(?<seconds>[0-9.]+s)?/gu;
const m = exp.exec(input);
const hours = m?.groups?.['hours'];
const minutes = m?.groups?.['minutes'];
const seconds = lessThanSecond ? input : m?.groups?.['seconds'];
if (!lessThanSecond && !hours && !minutes && !seconds) {
throw ERR_NO_TIME_UNITS;
}
if (seconds) {
S = parseFloat(seconds);
if (seconds.includes('ns')) S /= 1000 * 1000;
else if (seconds.includes('µs')) S /= 1000;
else if (seconds.includes('ms')) S *= 1;
else if (seconds.includes('s')) S *= 1000;
}
if (minutes && !lessThanSecond) {
M = parseFloat(minutes) * 60 * 1000;
}
if (hours && !lessThanSecond) {
H = parseFloat(hours) * 60 * 60 * 1000;
}
return H + M + S;
};
const useAverageBlockDuration = (polls = DEFAULT_POLLS) => {
const [avg, setAvg] = useState<number | undefined>(undefined);
const { data, startPolling, stopPolling, error } = useBlockStatisticsQuery({
@ -28,7 +74,11 @@ const useAverageBlockDuration = (polls = DEFAULT_POLLS) => {
useEffect(() => {
if (durations.length < polls && data) {
durations.push(parseFloat(data.statistics.blockDuration));
try {
durations.push(parseDuration(data.statistics.blockDuration)); // ms
} catch (err) {
// NOOP - do not add unparsed value to AVG
}
}
if (durations.length === polls) {
const averageBlockDuration = sum(durations) / durations.length; // ms