From d5eb49d8501c3833ae4b34d5ad63b22107559f46 Mon Sep 17 00:00:00 2001 From: onmax Date: Mon, 18 Nov 2024 16:59:04 -0600 Subject: [PATCH] chore: fixed endpoint --- packages/nimiq-validators-score/src/utils.ts | 2 + server/api/[version]/validators/index.get.ts | 12 +--- server/database/schema.ts | 6 +- server/utils/schemas.ts | 1 - server/utils/scores.ts | 16 ++--- server/utils/validators.ts | 76 +++++++++----------- 6 files changed, 49 insertions(+), 64 deletions(-) diff --git a/packages/nimiq-validators-score/src/utils.ts b/packages/nimiq-validators-score/src/utils.ts index 52eb58c..b57800a 100644 --- a/packages/nimiq-validators-score/src/utils.ts +++ b/packages/nimiq-validators-score/src/utils.ts @@ -15,6 +15,8 @@ interface GetRangeOptions { export const DEFAULT_WINDOW_IN_DAYS = 30 * 9 export const DEFAULT_WINDOW_IN_MS = DEFAULT_WINDOW_IN_DAYS * 24 * 60 * 60 * 1000 +const EPOCHS_PER_DAY = 2 +export const DEFAULT_WINDOW_IN_EPOCHS = DEFAULT_WINDOW_IN_DAYS * EPOCHS_PER_DAY /** * Given the amount of milliseconds we want to consider, it returns an object with the epoch range we will consider. diff --git a/server/api/[version]/validators/index.get.ts b/server/api/[version]/validators/index.get.ts index f7f6b71..6768010 100644 --- a/server/api/[version]/validators/index.get.ts +++ b/server/api/[version]/validators/index.get.ts @@ -16,19 +16,11 @@ export default defineCachedEventHandler(async (event) => { addresses = activeValidators.map(v => v.address) } - let epochNumber = -1 - if (params['with-scores']) { - const { data: currentEpoch, error: errorCurrentEpoch } = await getRpcClient().blockchain.getEpochNumber() - if (errorCurrentEpoch) - return createError(errorCurrentEpoch) - epochNumber = currentEpoch - 1 - } - - const { data: validators, error: errorValidators } = await fetchValidators({ ...params, addresses, epochNumber }) + const { data: validators, error: errorValidators } = await fetchValidators({ ...params, addresses }) if (errorValidators || !validators) throw createError(errorValidators) return validators }, { - maxAge: import.meta.dev ? 1 : 60 * 10, // 10 minutes + maxAge: import.meta.dev ? 0 : 60 * 10, // 10 minutes }) diff --git a/server/database/schema.ts b/server/database/schema.ts index 6ae32c3..3c04568 100644 --- a/server/database/schema.ts +++ b/server/database/schema.ts @@ -24,10 +24,10 @@ export const validators = sqliteTable('validators', { ), })) +// The scores only for the default window size export const scores = sqliteTable('scores', { validatorId: integer('validator_id').notNull().references(() => validators.id, { onDelete: 'cascade' }), - fromEpoch: integer('from_epoch').notNull(), - toEpoch: integer('to_epoch').notNull(), + epochNumber: integer('epoch_number').notNull(), total: real('total').notNull(), liveness: real('liveness').notNull(), size: real('size').notNull(), @@ -35,7 +35,7 @@ export const scores = sqliteTable('scores', { reason: text('reason', { mode: 'json' }).notNull(), }, table => ({ idxValidatorId: index('idx_validator_id').on(table.validatorId), - compositePrimaryKey: primaryKey({ columns: [table.validatorId, table.fromEpoch, table.toEpoch] }), + compositePrimaryKey: primaryKey({ columns: [table.validatorId, table.epochNumber] }), })) export const activity = sqliteTable('activity', { diff --git a/server/utils/schemas.ts b/server/utils/schemas.ts index fae998b..dbd650e 100644 --- a/server/utils/schemas.ts +++ b/server/utils/schemas.ts @@ -56,5 +56,4 @@ export const mainQuerySchema = z.object({ 'only-active': z.literal('true').or(z.literal('false')).default('false').transform(v => v === 'true'), 'only-known': z.literal('true').or(z.literal('false')).default('true').transform(v => v === 'true'), 'with-identicons': z.literal('true').or(z.literal('false')).default('false').transform(v => v === 'true'), - 'with-scores': z.literal('true').or(z.literal('false')).default('false').transform(v => v === 'true'), }) diff --git a/server/utils/scores.ts b/server/utils/scores.ts index aadf17c..da300bf 100644 --- a/server/utils/scores.ts +++ b/server/utils/scores.ts @@ -3,7 +3,7 @@ import type { NewScore } from './drizzle' import type { Result, ValidatorScore } from './types' import { consola } from 'consola' import { gte, inArray, lte } from 'drizzle-orm' -import { computeScore } from 'nimiq-validators-score' +import { computeScore, DEFAULT_WINDOW_IN_DAYS } from 'nimiq-validators-score' import { findMissingEpochs } from './activities' import { fetchValidatorsScoreByIds } from './validators' @@ -93,12 +93,15 @@ export async function calculateScores(range: Range): Result { } const score = computeScore({ liveness, size, reliability }) - const newScore: NewScore = { validatorId: Number(validatorId), fromEpoch: range.fromEpoch, toEpoch: range.toEpoch, ...score, reason } + const newScore: NewScore = { validatorId: Number(validatorId), epochNumber: range.toEpoch, ...score, reason } return newScore }) - // TODO only store the scores that uses default window size to save space - await persistScores(scores) + // If the range is the default window size or the range starts at the PoS fork block, we persist the scores + // TODO Once the chain is older than 9 months, we should remove range.fromBlockNumber === 1 + if (range.toEpoch - range.fromEpoch + 1 === DEFAULT_WINDOW_IN_DAYS || range.fromBlockNumber === 1) + await persistScores(scores) + const { data: validators, error: errorValidators } = await fetchValidatorsScoreByIds(scores.map(s => s.validatorId)) if (errorValidators || !validators) return { error: errorValidators, data: undefined } @@ -124,10 +127,7 @@ export async function checkIfScoreExistsInDb(range: Range) { const scoreAlreadyInDb = await useDrizzle() .select({ validatorId: tables.scores.validatorId }) .from(tables.scores) - .where(and( - eq(tables.scores.toEpoch, range.toEpoch), - eq(tables.scores.fromEpoch, range.fromEpoch), - )) + .where(eq(tables.scores.epochNumber, range.toEpoch)) .get() .then(r => Boolean(r?.validatorId)) return scoreAlreadyInDb diff --git a/server/utils/validators.ts b/server/utils/validators.ts index 4a9dd7c..daaad80 100644 --- a/server/utils/validators.ts +++ b/server/utils/validators.ts @@ -1,4 +1,3 @@ -import type { ScoreValues } from '~~/packages/nimiq-validators-score/src' import type { SQLWrapper } from 'drizzle-orm' import type { Validator } from './drizzle' import type { ValidatorJSON } from './schemas' @@ -123,13 +122,16 @@ export async function fetchValidatorsScoreByIds(validatorIds: number[]): Result< return { data: validators, error: undefined } } -export type FetchValidatorsOptions = Zod.infer & { addresses: string[], epochNumber?: number } +export type FetchValidatorsOptions = Zod.infer & { addresses: string[] } -type FetchedValidator = Omit & { icon?: string } & { score?: ScoreValues | null, sizeRatio?: number } +type FetchedValidator = Omit & { + icon?: string + score?: { total: number, liveness: number, size: number, reliability: number } +} export async function fetchValidators(params: FetchValidatorsOptions): Result { - // This function is a mess. It should be refactored and create better API - const { 'payout-type': payoutType, addresses = [], 'only-known': onlyKnown = false, 'with-identicons': withIdenticons = false, 'with-scores': withScores = false, epochNumber = -1 } = params + const { 'payout-type': payoutType, addresses = [], 'only-known': onlyKnown = false, 'with-identicons': withIdenticons = false } = params + const filters: SQLWrapper[] = [isNotNull(tables.scores.validatorId)] if (payoutType) filters.push(eq(tables.validators.payoutType, payoutType)) @@ -138,49 +140,39 @@ export async function fetchValidators(params: FetchValidatorsOptions): Result v.hasDefaultIcon).forEach(v => delete v.icon)