From fc505fca6854458596f9476238671be8e3f3d3e6 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Wed, 9 Apr 2025 15:56:00 +0200 Subject: [PATCH 01/16] Evaluate network wide measurement --- lib/preprocess.js | 28 ++++++++++++++++ lib/public-stats.js | 32 +++++++++++++++++++ lib/typings.d.ts | 4 +++ ...add-network-wide-retrieval-stats-table.sql | 5 +++ test/helpers/test-data.js | 7 +++- 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 migrations/026.do.add-network-wide-retrieval-stats-table.sql diff --git a/lib/preprocess.js b/lib/preprocess.js index 7092bfb0..c44e1f2f 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -17,6 +17,7 @@ export class Measurement { constructor (m, pointerize = (v) => v) { this.participantAddress = pointerize(parseParticipantAddress(m.participant_address)) this.retrievalResult = pointerize(getRetrievalResult(m)) + this.networkRetrievalResult = pointerize(getRetrievalResult(m)) this.cid = pointerize(m.cid) this.minerId = pointerize(m.miner_id) // Note: providerId is recorded by spark-publish but we don't use it for evaluations yet @@ -41,6 +42,10 @@ export class Measurement { this.stationId = pointerize(m.station_id) this.carChecksum = pointerize(m.car_checksum) this.carTooLarge = m.car_too_large + this.networkRetrievalStatusCode = m.network_retrieval_status_code + this.networkRetrievalTimeout = m.network_retrieval_timeout + this.networkRetrievalCarTooLarge = m.network_retrieval_car_too_large + this.networkRetrievalEndAt = m.network_retrieval_end_at } } @@ -319,3 +324,26 @@ export const getRetrievalResult = (measurement) => { return ok ? 'OK' : 'UNKNOWN_ERROR' } + +/** + * @param {Partial} measurement + * @return {import('./typings.js').RetrievalResult} + */ +export const getNetworkRetrievalResult = (measurement) => { + const providerRetrievalResult = getRetrievalResult(measurement) + if (providerRetrievalResult !== 'IPNI_NO_VALID_ADVERTISEMENT') { + return providerRetrievalResult + } + + /** @type {Partial} */ + const networkMeasurement = { + indexer_result: 'OK', + status_code: measurement.network_retrieval_status_code, + timeout: measurement.network_retrieval_timeout, + network_retrieval_status_code: measurement.network_retrieval_status_code, + car_too_large: measurement.network_retrieval_car_too_large, + end_at: measurement.network_retrieval_end_at + } + + return getRetrievalResult(networkMeasurement) +} diff --git a/lib/public-stats.js b/lib/public-stats.js index d0a4197d..9ec86bfb 100644 --- a/lib/public-stats.js +++ b/lib/public-stats.js @@ -30,6 +30,7 @@ export const updatePublicStats = async ({ createPgClient, committees, allMeasure await updateRetrievalTimings(pgClient, committees) await updateDailyClientRetrievalStats(pgClient, committees, findDealClients) await updateDailyAllocatorRetrievalStats(pgClient, committees, findDealAllocators) + await updateNetworkRetrievalStats(pgClient, committees) } finally { await pgClient.end() } @@ -407,3 +408,34 @@ function buildPerPartyStats (committees, perDealParty, partyName) { ) return flatStats } + +/** + * @param {pg.Client} pgClient + * @param {object} stats + * @param {number} stats.total + * @param {number} stats.successful + */ +export const updateNetworkRetrievalStats = async (pgClient, committees) => { + let total = 0 + let successful = 0 + for (const c of committees) { + for (const m of c.measurements) { + if (m.networkRetrievalResult === 'OK') successful++ + total++ + } + } + + debug('Updating public network wide retrieval stats: total += %s successful += %s', total, successful) + await pgClient.query(` + INSERT INTO network_retrieval_stats + (day, total, successful) + VALUES + (now(), $1, $2) + ON CONFLICT(day) DO UPDATE SET + total = network_retrieval_stats.total + $1, + successful = network_retrieval_stats.successful + $2 + `, [ + total, + successful + ]) +} diff --git a/lib/typings.d.ts b/lib/typings.d.ts index 1963e72c..66e23abd 100644 --- a/lib/typings.d.ts +++ b/lib/typings.d.ts @@ -100,6 +100,10 @@ export interface RawMeasurement { | 'NO_VALID_ADVERTISEMENT' | 'ERROR_FETCH' | `ERROR_${number}`; + network_retrieval_status_code: number | undefined | null; + network_retrieval_timeout: boolean; + network_retrieval_car_too_large: boolean; + network_retrieval_end_at: string; } export type CreatePgClient = () => Promise; diff --git a/migrations/026.do.add-network-wide-retrieval-stats-table.sql b/migrations/026.do.add-network-wide-retrieval-stats-table.sql new file mode 100644 index 00000000..25c20044 --- /dev/null +++ b/migrations/026.do.add-network-wide-retrieval-stats-table.sql @@ -0,0 +1,5 @@ +CREATE TABLE network_retrieval_stats ( + day DATE NOT NULL PRIMARY KEY, + total INT NOT NULL, + successful INT NOT NULL +); diff --git a/test/helpers/test-data.js b/test/helpers/test-data.js index 7c9e7481..d8d0cea0 100644 --- a/test/helpers/test-data.js +++ b/test/helpers/test-data.js @@ -43,7 +43,12 @@ export const VALID_MEASUREMENT = { retrievalResult: 'OK', indexerResult: 'OK', taskingEvaluation: null, - consensusEvaluation: null + consensusEvaluation: null, + networkRetrievalResult: 'OK', + networkRetrievalStatusCode: null, + networkRetrievalTimeout: false, + networkRetrievalCarTooLarge: false, + networkRetrievalEndAt: null } // Fraud detection is mutating the measurements parsed from JSON From 45deeb048bddfdd5347d85c2591fef7848526370 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Wed, 9 Apr 2025 18:07:22 +0200 Subject: [PATCH 02/16] Include network RSR to retrieval stats; Rename table --- lib/preprocess.js | 2 +- lib/public-stats.js | 12 ++--- lib/retrieval-stats.js | 5 +++ ...d-daily-network-retrieval-stats-table.sql} | 2 +- test/public-stats.test.js | 44 ++++++++++++++++--- test/retrieval-stats.test.js | 20 +++++++++ 6 files changed, 72 insertions(+), 13 deletions(-) rename migrations/{026.do.add-network-wide-retrieval-stats-table.sql => 026.do.add-daily-network-retrieval-stats-table.sql} (65%) diff --git a/lib/preprocess.js b/lib/preprocess.js index c44e1f2f..c79f2ad7 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -331,7 +331,7 @@ export const getRetrievalResult = (measurement) => { */ export const getNetworkRetrievalResult = (measurement) => { const providerRetrievalResult = getRetrievalResult(measurement) - if (providerRetrievalResult !== 'IPNI_NO_VALID_ADVERTISEMENT') { + if (providerRetrievalResult !== 'IPNI_NO_VALID_ADVERTISEMENT' || !measurement.network_retrieval_status_code) { return providerRetrievalResult } diff --git a/lib/public-stats.js b/lib/public-stats.js index 9ec86bfb..80c5caee 100644 --- a/lib/public-stats.js +++ b/lib/public-stats.js @@ -30,7 +30,7 @@ export const updatePublicStats = async ({ createPgClient, committees, allMeasure await updateRetrievalTimings(pgClient, committees) await updateDailyClientRetrievalStats(pgClient, committees, findDealClients) await updateDailyAllocatorRetrievalStats(pgClient, committees, findDealAllocators) - await updateNetworkRetrievalStats(pgClient, committees) + await updateDailyNetworkRetrievalStats(pgClient, committees) } finally { await pgClient.end() } @@ -415,7 +415,7 @@ function buildPerPartyStats (committees, perDealParty, partyName) { * @param {number} stats.total * @param {number} stats.successful */ -export const updateNetworkRetrievalStats = async (pgClient, committees) => { +export const updateDailyNetworkRetrievalStats = async (pgClient, committees) => { let total = 0 let successful = 0 for (const c of committees) { @@ -425,15 +425,15 @@ export const updateNetworkRetrievalStats = async (pgClient, committees) => { } } - debug('Updating public network wide retrieval stats: total += %s successful += %s', total, successful) + debug('Updating public daily network wide retrieval stats: total += %s successful += %s', total, successful) await pgClient.query(` - INSERT INTO network_retrieval_stats + INSERT INTO daily_network_retrieval_stats (day, total, successful) VALUES (now(), $1, $2) ON CONFLICT(day) DO UPDATE SET - total = network_retrieval_stats.total + $1, - successful = network_retrieval_stats.successful + $2 + total = daily_network_retrieval_stats.total + $1, + successful = daily_network_retrieval_stats.successful + $2 `, [ total, successful diff --git a/lib/retrieval-stats.js b/lib/retrieval-stats.js index b56c44c9..155af676 100644 --- a/lib/retrieval-stats.js +++ b/lib/retrieval-stats.js @@ -60,6 +60,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { const sizeValues = [] let httpSuccesses = 0 let indexerServerErrorCount = 0 + let networkRetrievalSuccesses = 0 for (const m of measurements) { // `retrievalResult` should be always set by lib/preprocess.js, so we should never encounter @@ -106,6 +107,8 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { // A successful HTTP response is a response with result breakdown set to OK and the protocol being used is set to HTTP. if (m.retrievalResult === 'OK' && m.protocol === 'http') { httpSuccesses++ } + if (m.networkRetrievalResult === 'OK') { networkRetrievalSuccesses++ } + if (m.retrievalResult.match(/^IPNI_ERROR_5\d\d$/)) { indexerServerErrorCount++ } @@ -114,6 +117,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { const totalForRSR = totalCount - indexerServerErrorCount const successRate = totalForRSR ? resultBreakdown.OK / totalForRSR : 0 const successRateHttp = totalForRSR ? httpSuccesses / totalForRSR : 0 + const networkRSR = totalForRSR ? networkRetrievalSuccesses / totalForRSR : 0 telemetryPoint.intField('total_for_success_rates', totalForRSR) telemetryPoint.intField('unique_tasks', uniqueTasksCount) telemetryPoint.floatField('success_rate', successRate) @@ -122,6 +126,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { telemetryPoint.intField('inet_groups', inetGroups.size) telemetryPoint.intField('measurements', totalCount) telemetryPoint.intField('download_bandwidth', downloadBandwidth) + telemetryPoint.floatField('network_success_rate', networkRSR) addHistogramToPoint(telemetryPoint, ttfbValues, 'ttfb_') addHistogramToPoint(telemetryPoint, durationValues, 'duration_') diff --git a/migrations/026.do.add-network-wide-retrieval-stats-table.sql b/migrations/026.do.add-daily-network-retrieval-stats-table.sql similarity index 65% rename from migrations/026.do.add-network-wide-retrieval-stats-table.sql rename to migrations/026.do.add-daily-network-retrieval-stats-table.sql index 25c20044..e8310d29 100644 --- a/migrations/026.do.add-network-wide-retrieval-stats-table.sql +++ b/migrations/026.do.add-daily-network-retrieval-stats-table.sql @@ -1,4 +1,4 @@ -CREATE TABLE network_retrieval_stats ( +CREATE TABLE daily_network_retrieval_stats ( day DATE NOT NULL PRIMARY KEY, total INT NOT NULL, successful INT NOT NULL diff --git a/test/public-stats.test.js b/test/public-stats.test.js index 2b61d693..dd38eda3 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -4,7 +4,7 @@ import pg from 'pg' import { DATABASE_URL } from '../lib/config.js' import { migrateWithPgClient } from '../lib/migrate.js' import { buildEvaluatedCommitteesFromMeasurements, VALID_MEASUREMENT } from './helpers/test-data.js' -import { updateDailyAllocatorRetrievalStats, updateDailyClientRetrievalStats, updatePublicStats } from '../lib/public-stats.js' +import { updateDailyAllocatorRetrievalStats, updateDailyClientRetrievalStats, updateDailyNetworkRetrievalStats, updatePublicStats } from '../lib/public-stats.js' import { beforeEach } from 'mocha' import { groupMeasurementsToCommittees } from '../lib/committee.js' @@ -724,7 +724,7 @@ describe('public-stats', () => { findDealClients ) const { rows } = await pgClient.query( - `SELECT + `SELECT day::TEXT, client_id, total, @@ -770,7 +770,7 @@ describe('public-stats', () => { findDealClients ) const { rows } = await pgClient.query( - `SELECT + `SELECT day::TEXT, client_id, total, @@ -965,7 +965,7 @@ describe('public-stats', () => { findDealAllocators ) const { rows } = await pgClient.query( - `SELECT + `SELECT day::TEXT, allocator_id, total, @@ -1011,7 +1011,7 @@ describe('public-stats', () => { findDealAllocators ) const { rows } = await pgClient.query( - `SELECT + `SELECT day::TEXT, allocator_id, total, @@ -1168,6 +1168,40 @@ describe('public-stats', () => { { day: today, allocator_id: 'f0allocator', total: 4, successful: 3 } ]) }) + + describe('updateDailyNetworkRetrievalStats ', () => { + it('creates or updates the row for today', async () => { + /** @type {Measurement[]} */ + const allMeasurements = [ + { ...VALID_MEASUREMENT, networkRetrievalResult: 'OK' }, + { ...VALID_MEASUREMENT, networkRetrievalResult: 'OK' }, + + { ...VALID_MEASUREMENT, networkRetrievalResult: 'TIMEOUT' }, + { ...VALID_MEASUREMENT, networkRetrievalResult: 'CAR_TOO_LARGE' }, + { ...VALID_MEASUREMENT, networkRetrievalResult: 'IPNI_ERROR_FETCH' } + ] + + const committees = groupMeasurementsToCommittees(allMeasurements) + const { rows: created } = await pgClient.query( + 'SELECT * FROM daily_network_retrieval_stats' + ) + assert.deepStrictEqual(created, []) + await updateDailyNetworkRetrievalStats( + pgClient, + committees + ) + const { rows } = await pgClient.query( + `SELECT + day::TEXT, + total, + successful + FROM daily_network_retrieval_stats`) + + assert.deepStrictEqual(rows, [ + { day: today, total: 5, successful: 2 } + ]) + }) + }) }) const getCurrentDate = async () => { diff --git a/test/retrieval-stats.test.js b/test/retrieval-stats.test.js index dba0350b..55c442d0 100644 --- a/test/retrieval-stats.test.js +++ b/test/retrieval-stats.test.js @@ -324,6 +324,26 @@ describe('retrieval statistics', () => { // Only one of the successful measurements used http assertPointFieldValue(point, 'success_rate_http', '0.25') }) + + it('records network retrieval success rate', async () => { + /** @type {Measurement[]} */ + const measurements = [ + { + ...VALID_MEASUREMENT, + networkRetrievalResult: 'OK' + }, + { + ...VALID_MEASUREMENT, + networkRetrievalResult: 'HTTP_500' + } + ] + + const point = new Point('stats') + buildRetrievalStats(measurements, point) + debug('stats', point.fields) + + assertPointFieldValue(point, 'network_success_rate', '0.5') + }) }) describe('getValueAtPercentile', () => { From 8aa8f7c26aa829a7c52efc113eb219df0fee0882 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Wed, 9 Apr 2025 19:15:21 +0200 Subject: [PATCH 03/16] Fix failing test --- test/public-stats.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/public-stats.test.js b/test/public-stats.test.js index dd38eda3..a7a61765 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -1181,7 +1181,7 @@ describe('public-stats', () => { { ...VALID_MEASUREMENT, networkRetrievalResult: 'IPNI_ERROR_FETCH' } ] - const committees = groupMeasurementsToCommittees(allMeasurements) + const committees = buildEvaluatedCommitteesFromMeasurements(allMeasurements) const { rows: created } = await pgClient.query( 'SELECT * FROM daily_network_retrieval_stats' ) From fe463117c9adaac66b775f1a3b891e898365b62b Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Wed, 9 Apr 2025 19:19:22 +0200 Subject: [PATCH 04/16] Delete from table before tests --- test/public-stats.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/public-stats.test.js b/test/public-stats.test.js index a7a61765..43eb643c 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -31,6 +31,7 @@ describe('public-stats', () => { await pgClient.query('DELETE FROM retrieval_timings') await pgClient.query('DELETE FROM daily_client_retrieval_stats') await pgClient.query('DELETE FROM daily_allocator_retrieval_stats') + await pgClient.query('DELETE FROM daily_network_retrieval_stats') // Run all tests inside a transaction to ensure `now()` always returns the same value // See https://dba.stackexchange.com/a/63549/125312 From bfe90c09e7efe6a54a6b22c88ea90a362231055e Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Thu, 10 Apr 2025 11:39:08 +0200 Subject: [PATCH 05/16] Convert network measurement to object inside the measurement --- lib/preprocess.js | 19 +++++++++++-------- lib/typings.d.ts | 1 + test/helpers/test-data.js | 11 +++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index c79f2ad7..5a40a32b 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -42,10 +42,13 @@ export class Measurement { this.stationId = pointerize(m.station_id) this.carChecksum = pointerize(m.car_checksum) this.carTooLarge = m.car_too_large - this.networkRetrievalStatusCode = m.network_retrieval_status_code - this.networkRetrievalTimeout = m.network_retrieval_timeout - this.networkRetrievalCarTooLarge = m.network_retrieval_car_too_large - this.networkRetrievalEndAt = m.network_retrieval_end_at + this.networkRetrieval = { + statusCode: m.network_retrieval_status_code, + timeout: m.network_retrieval_timeout, + carTooLarge: m.network_retrieval_car_too_large, + endAt: m.network_retrieval_end_at, + protocol: m.network_retrieval_protocol + } } } @@ -330,9 +333,8 @@ export const getRetrievalResult = (measurement) => { * @return {import('./typings.js').RetrievalResult} */ export const getNetworkRetrievalResult = (measurement) => { - const providerRetrievalResult = getRetrievalResult(measurement) - if (providerRetrievalResult !== 'IPNI_NO_VALID_ADVERTISEMENT' || !measurement.network_retrieval_status_code) { - return providerRetrievalResult + if (!measurement.network_retrieval_status_code) { + return getRetrievalResult(measurement) } /** @type {Partial} */ @@ -342,7 +344,8 @@ export const getNetworkRetrievalResult = (measurement) => { timeout: measurement.network_retrieval_timeout, network_retrieval_status_code: measurement.network_retrieval_status_code, car_too_large: measurement.network_retrieval_car_too_large, - end_at: measurement.network_retrieval_end_at + end_at: measurement.network_retrieval_end_at, + protocol: measurement.network_retrieval_protocol } return getRetrievalResult(networkMeasurement) diff --git a/lib/typings.d.ts b/lib/typings.d.ts index 66e23abd..26b5894e 100644 --- a/lib/typings.d.ts +++ b/lib/typings.d.ts @@ -104,6 +104,7 @@ export interface RawMeasurement { network_retrieval_timeout: boolean; network_retrieval_car_too_large: boolean; network_retrieval_end_at: string; + network_retrieval_protocol: string; } export type CreatePgClient = () => Promise; diff --git a/test/helpers/test-data.js b/test/helpers/test-data.js index d8d0cea0..3e6837d2 100644 --- a/test/helpers/test-data.js +++ b/test/helpers/test-data.js @@ -45,10 +45,13 @@ export const VALID_MEASUREMENT = { taskingEvaluation: null, consensusEvaluation: null, networkRetrievalResult: 'OK', - networkRetrievalStatusCode: null, - networkRetrievalTimeout: false, - networkRetrievalCarTooLarge: false, - networkRetrievalEndAt: null + networkRetrieval: { + statusCode: null, + timeout: false, + carTooLarge: false, + endAt: null, + protocol: 'http' + } } // Fraud detection is mutating the measurements parsed from JSON From 80ccb19de09191f383132229f9b62d47188ba4df Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Thu, 10 Apr 2025 12:47:36 +0200 Subject: [PATCH 06/16] fix: Use getNetworkRetrievalResult to evaluate network retrieval measurement --- lib/preprocess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index 5a40a32b..ec9da49a 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -17,7 +17,7 @@ export class Measurement { constructor (m, pointerize = (v) => v) { this.participantAddress = pointerize(parseParticipantAddress(m.participant_address)) this.retrievalResult = pointerize(getRetrievalResult(m)) - this.networkRetrievalResult = pointerize(getRetrievalResult(m)) + this.networkRetrievalResult = pointerize(getNetworkRetrievalResult(m)) this.cid = pointerize(m.cid) this.minerId = pointerize(m.miner_id) // Note: providerId is recorded by spark-publish but we don't use it for evaluations yet From 250380d669af67df4b07eea7e1c60a92b00c4de7 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Thu, 10 Apr 2025 13:01:27 +0200 Subject: [PATCH 07/16] Add tests for getNetworkRetrievalResult --- lib/preprocess.js | 7 +++- test/preprocess.js | 88 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index ec9da49a..8529a827 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -329,11 +329,16 @@ export const getRetrievalResult = (measurement) => { } /** + * Evaluates the network retrieval result. + * + * Network retrieval results are evaluated only if the indexer result is `NO_VALID_ADVERTISEMENT` + * and the network retrieval status code is set. + * * @param {Partial} measurement * @return {import('./typings.js').RetrievalResult} */ export const getNetworkRetrievalResult = (measurement) => { - if (!measurement.network_retrieval_status_code) { + if (measurement.indexer_result !== 'NO_VALID_ADVERTISEMENT' || !measurement.network_retrieval_status_code) { return getRetrievalResult(measurement) } diff --git a/test/preprocess.js b/test/preprocess.js index d15d94bf..13fdf543 100644 --- a/test/preprocess.js +++ b/test/preprocess.js @@ -4,7 +4,8 @@ import { preprocess, Measurement, parseMeasurements, - assertValidMeasurement + assertValidMeasurement, + getNetworkRetrievalResult } from '../lib/preprocess.js' import { Point } from '../lib/telemetry.js' import assert from 'node:assert' @@ -416,3 +417,88 @@ describe('assertValidMeasurement', () => { assert.throws(() => assertValidMeasurement(measurement), /first_byte_at must be greater than or equal to start_at/) }) }) + +describe('getNetworkRetrievalResult ', () => { + /** @type {Partial} */ + const SUCCESSFUL_RETRIEVAL = { + spark_version: '1.5.2', + participant_address: 'f410fgkhpcrbmdvic52o3nivftrjxr7nzw47updmuzra', + station_id: VALID_STATION_ID, + finished_at: '2023-11-01T09:42:03.246Z', + timeout: false, + start_at: '2023-11-01T09:40:03.393Z', + status_code: 200, + first_byte_at: '1970-01-01T00:00:00.000Z', + end_at: '1970-01-01T00:00:00.000Z', + byte_length: 1234, + inet_group: 'ue49TX_JdYjI', + cid: 'bafkreihstuf2qcu3hs64ersidh46cjtilxcoipmzgu3pifwzmkqdjpraqq', + miner_id: 'f1abc', + provider_address: '/ip4/108.89.91.150/tcp/46717/p2p/12D3KooWSsaFCtzDJUEhLQYDdwoFtdCMqqfk562UMvccFz12kYxU', + provider_id: 'PROVIDERID', + protocol: 'http', + indexer_result: 'OK' + } + + it('successful retrieval', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL + }) + assert.strictEqual(result, 'OK') + }) + + it('TIMEOUT - no network retrieval measurements', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL, + timeout: true + }) + assert.strictEqual(result, 'TIMEOUT') + }) + + it('TIMEOUT - successful network retrieval measurements', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL, + timeout: true, + network_retrieval_car_too_large: false, + network_retrieval_timeout: false, + network_retrieval_status_code: 200, + network_retrieval_end_at: '2023-11-01T09:42:03.246Z', + network_retrieval_protocol: 'http' + }) + assert.strictEqual(result, 'TIMEOUT') + }) + + it('NO_VALID_ADVERTISEMENT - no network retrieval measurements', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL, + indexer_result: 'NO_VALID_ADVERTISEMENT' + }) + assert.strictEqual(result, 'IPNI_NO_VALID_ADVERTISEMENT') + }) + + it('NO_VALID_ADVERTISEMENT - successful network retrieval measurements', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL, + indexer_result: 'NO_VALID_ADVERTISEMENT', + network_retrieval_car_too_large: false, + network_retrieval_timeout: false, + network_retrieval_status_code: 200, + network_retrieval_end_at: '2023-11-01T09:42:03.246Z', + network_retrieval_protocol: 'http' + }) + assert.strictEqual(result, 'OK') + }) + + it('NO_VALID_ADVERTISEMENT - TIMEOUT network retrieval measurements', () => { + const result = getNetworkRetrievalResult({ + ...SUCCESSFUL_RETRIEVAL, + indexer_result: 'NO_VALID_ADVERTISEMENT', + network_retrieval_car_too_large: false, + network_retrieval_timeout: true, + network_retrieval_status_code: 500, + network_retrieval_end_at: '2023-11-01T09:42:03.246Z', + network_retrieval_protocol: 'http' + }) + assert.strictEqual(result, 'TIMEOUT') + }) +}) From ab8046025c468992e1c3e15b4b1c1e1d6c894a87 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Thu, 10 Apr 2025 13:04:10 +0200 Subject: [PATCH 08/16] Remove extra trailing whitespace in test name --- test/preprocess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/preprocess.js b/test/preprocess.js index 13fdf543..42c9eab2 100644 --- a/test/preprocess.js +++ b/test/preprocess.js @@ -418,7 +418,7 @@ describe('assertValidMeasurement', () => { }) }) -describe('getNetworkRetrievalResult ', () => { +describe('getNetworkRetrievalResult', () => { /** @type {Partial} */ const SUCCESSFUL_RETRIEVAL = { spark_version: '1.5.2', From 1a1a10a9e56248132845df342da11375b3e60b0b Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 18:49:51 +0200 Subject: [PATCH 09/16] Refactor network retrieval to alternative provider retrieval --- lib/preprocess.js | 38 ++++++------- lib/retrieval-stats.js | 2 +- lib/typings.d.ts | 10 ++-- ...native-provider-retrieval-stats-table.sql} | 2 +- test/helpers/test-data.js | 4 +- test/preprocess.js | 56 +++++++++---------- test/public-stats.test.js | 16 +++--- test/retrieval-stats.test.js | 4 +- 8 files changed, 66 insertions(+), 66 deletions(-) rename migrations/{026.do.add-daily-network-retrieval-stats-table.sql => 026.do.add-daily-alternative-provider-retrieval-stats-table.sql} (59%) diff --git a/lib/preprocess.js b/lib/preprocess.js index 8529a827..f255b36f 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -17,7 +17,7 @@ export class Measurement { constructor (m, pointerize = (v) => v) { this.participantAddress = pointerize(parseParticipantAddress(m.participant_address)) this.retrievalResult = pointerize(getRetrievalResult(m)) - this.networkRetrievalResult = pointerize(getNetworkRetrievalResult(m)) + this.alternativeProviderRetrievalResult = pointerize(getAlternativeProviderRetrievalResult(m)) this.cid = pointerize(m.cid) this.minerId = pointerize(m.miner_id) // Note: providerId is recorded by spark-publish but we don't use it for evaluations yet @@ -42,12 +42,12 @@ export class Measurement { this.stationId = pointerize(m.station_id) this.carChecksum = pointerize(m.car_checksum) this.carTooLarge = m.car_too_large - this.networkRetrieval = { - statusCode: m.network_retrieval_status_code, - timeout: m.network_retrieval_timeout, - carTooLarge: m.network_retrieval_car_too_large, - endAt: m.network_retrieval_end_at, - protocol: m.network_retrieval_protocol + this.alternativeProviderCheck = { + statusCode: m.alternative_provider_check_status_code, + timeout: m.alternative_provider_check_timeout, + carTooLarge: m.alternative_provider_check_car_too_large, + endAt: m.alternative_provider_check_end_at, + protocol: m.alternative_provider_check_protocol } } } @@ -329,29 +329,29 @@ export const getRetrievalResult = (measurement) => { } /** - * Evaluates the network retrieval result. + * Evaluates the alternative provider retrieval result. * - * Network retrieval results are evaluated only if the indexer result is `NO_VALID_ADVERTISEMENT` + * Alternative provider retrieval results are evaluated only if the indexer result is `NO_VALID_ADVERTISEMENT` * and the network retrieval status code is set. * * @param {Partial} measurement * @return {import('./typings.js').RetrievalResult} */ -export const getNetworkRetrievalResult = (measurement) => { - if (measurement.indexer_result !== 'NO_VALID_ADVERTISEMENT' || !measurement.network_retrieval_status_code) { +export const getAlternativeProviderRetrievalResult = (measurement) => { + if (measurement.indexer_result !== 'NO_VALID_ADVERTISEMENT' || !measurement.alternative_provider_check_status_code) { return getRetrievalResult(measurement) } /** @type {Partial} */ - const networkMeasurement = { + const alternativeProviderMeasurement = { indexer_result: 'OK', - status_code: measurement.network_retrieval_status_code, - timeout: measurement.network_retrieval_timeout, - network_retrieval_status_code: measurement.network_retrieval_status_code, - car_too_large: measurement.network_retrieval_car_too_large, - end_at: measurement.network_retrieval_end_at, - protocol: measurement.network_retrieval_protocol + status_code: measurement.alternative_provider_check_status_code, + timeout: measurement.alternative_provider_check_timeout, + alternative_provider_check_status_code: measurement.alternative_provider_check_status_code, + car_too_large: measurement.alternative_provider_check_car_too_large, + end_at: measurement.alternative_provider_check_end_at, + protocol: measurement.alternative_provider_check_protocol } - return getRetrievalResult(networkMeasurement) + return getRetrievalResult(alternativeProviderMeasurement) } diff --git a/lib/retrieval-stats.js b/lib/retrieval-stats.js index 155af676..c91d8898 100644 --- a/lib/retrieval-stats.js +++ b/lib/retrieval-stats.js @@ -107,7 +107,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { // A successful HTTP response is a response with result breakdown set to OK and the protocol being used is set to HTTP. if (m.retrievalResult === 'OK' && m.protocol === 'http') { httpSuccesses++ } - if (m.networkRetrievalResult === 'OK') { networkRetrievalSuccesses++ } + if (m.alternativeProviderRetrievalResult === 'OK') { networkRetrievalSuccesses++ } if (m.retrievalResult.match(/^IPNI_ERROR_5\d\d$/)) { indexerServerErrorCount++ diff --git a/lib/typings.d.ts b/lib/typings.d.ts index 26b5894e..abaa3849 100644 --- a/lib/typings.d.ts +++ b/lib/typings.d.ts @@ -100,11 +100,11 @@ export interface RawMeasurement { | 'NO_VALID_ADVERTISEMENT' | 'ERROR_FETCH' | `ERROR_${number}`; - network_retrieval_status_code: number | undefined | null; - network_retrieval_timeout: boolean; - network_retrieval_car_too_large: boolean; - network_retrieval_end_at: string; - network_retrieval_protocol: string; + alternative_provider_check_status_code: number | undefined | null; + alternative_provider_check_timeout: boolean; + alternative_provider_check_car_too_large: boolean; + alternative_provider_check_end_at: string; + alternative_provider_check_protocol: string; } export type CreatePgClient = () => Promise; diff --git a/migrations/026.do.add-daily-network-retrieval-stats-table.sql b/migrations/026.do.add-daily-alternative-provider-retrieval-stats-table.sql similarity index 59% rename from migrations/026.do.add-daily-network-retrieval-stats-table.sql rename to migrations/026.do.add-daily-alternative-provider-retrieval-stats-table.sql index e8310d29..d1d05124 100644 --- a/migrations/026.do.add-daily-network-retrieval-stats-table.sql +++ b/migrations/026.do.add-daily-alternative-provider-retrieval-stats-table.sql @@ -1,4 +1,4 @@ -CREATE TABLE daily_network_retrieval_stats ( +CREATE TABLE daily_alternative_provider_retrieval_stats ( day DATE NOT NULL PRIMARY KEY, total INT NOT NULL, successful INT NOT NULL diff --git a/test/helpers/test-data.js b/test/helpers/test-data.js index 3e6837d2..318e498b 100644 --- a/test/helpers/test-data.js +++ b/test/helpers/test-data.js @@ -44,8 +44,8 @@ export const VALID_MEASUREMENT = { indexerResult: 'OK', taskingEvaluation: null, consensusEvaluation: null, - networkRetrievalResult: 'OK', - networkRetrieval: { + alternativeProviderRetrievalResult: 'OK', + alternativeProviderCheck: { statusCode: null, timeout: false, carTooLarge: false, diff --git a/test/preprocess.js b/test/preprocess.js index 42c9eab2..9a412a97 100644 --- a/test/preprocess.js +++ b/test/preprocess.js @@ -5,7 +5,7 @@ import { Measurement, parseMeasurements, assertValidMeasurement, - getNetworkRetrievalResult + getAlternativeProviderRetrievalResult } from '../lib/preprocess.js' import { Point } from '../lib/telemetry.js' import assert from 'node:assert' @@ -418,7 +418,7 @@ describe('assertValidMeasurement', () => { }) }) -describe('getNetworkRetrievalResult', () => { +describe('getAlternativeProviderRetrievalResult', () => { /** @type {Partial} */ const SUCCESSFUL_RETRIEVAL = { spark_version: '1.5.2', @@ -441,63 +441,63 @@ describe('getNetworkRetrievalResult', () => { } it('successful retrieval', () => { - const result = getNetworkRetrievalResult({ + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL }) assert.strictEqual(result, 'OK') }) - it('TIMEOUT - no network retrieval measurements', () => { - const result = getNetworkRetrievalResult({ + it('TIMEOUT - no alternative provider retrieval measurements', () => { + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, timeout: true }) assert.strictEqual(result, 'TIMEOUT') }) - it('TIMEOUT - successful network retrieval measurements', () => { - const result = getNetworkRetrievalResult({ + it('TIMEOUT - successful alternative provider retrieval measurements', () => { + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, timeout: true, - network_retrieval_car_too_large: false, - network_retrieval_timeout: false, - network_retrieval_status_code: 200, - network_retrieval_end_at: '2023-11-01T09:42:03.246Z', - network_retrieval_protocol: 'http' + alternative_provider_check_car_too_large: false, + alternative_provider_check_timeout: false, + alternative_provider_check_status_code: 200, + alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', + alternative_provider_check_protocol: 'http' }) assert.strictEqual(result, 'TIMEOUT') }) - it('NO_VALID_ADVERTISEMENT - no network retrieval measurements', () => { - const result = getNetworkRetrievalResult({ + it('NO_VALID_ADVERTISEMENT - no alternative provider retrieval measurements', () => { + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, indexer_result: 'NO_VALID_ADVERTISEMENT' }) assert.strictEqual(result, 'IPNI_NO_VALID_ADVERTISEMENT') }) - it('NO_VALID_ADVERTISEMENT - successful network retrieval measurements', () => { - const result = getNetworkRetrievalResult({ + it('NO_VALID_ADVERTISEMENT - successful alternative provider retrieval measurements', () => { + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, indexer_result: 'NO_VALID_ADVERTISEMENT', - network_retrieval_car_too_large: false, - network_retrieval_timeout: false, - network_retrieval_status_code: 200, - network_retrieval_end_at: '2023-11-01T09:42:03.246Z', - network_retrieval_protocol: 'http' + alternative_provider_check_car_too_large: false, + alternative_provider_check_timeout: false, + alternative_provider_check_status_code: 200, + alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', + alternative_provider_check_protocol: 'http' }) assert.strictEqual(result, 'OK') }) - it('NO_VALID_ADVERTISEMENT - TIMEOUT network retrieval measurements', () => { - const result = getNetworkRetrievalResult({ + it('NO_VALID_ADVERTISEMENT - TIMEOUT alternative provider retrieval measurements', () => { + const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, indexer_result: 'NO_VALID_ADVERTISEMENT', - network_retrieval_car_too_large: false, - network_retrieval_timeout: true, - network_retrieval_status_code: 500, - network_retrieval_end_at: '2023-11-01T09:42:03.246Z', - network_retrieval_protocol: 'http' + alternative_provider_check_car_too_large: false, + alternative_provider_check_timeout: true, + alternative_provider_check_status_code: 500, + alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', + alternative_provider_check_protocol: 'http' }) assert.strictEqual(result, 'TIMEOUT') }) diff --git a/test/public-stats.test.js b/test/public-stats.test.js index 43eb643c..f20eef52 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -31,7 +31,7 @@ describe('public-stats', () => { await pgClient.query('DELETE FROM retrieval_timings') await pgClient.query('DELETE FROM daily_client_retrieval_stats') await pgClient.query('DELETE FROM daily_allocator_retrieval_stats') - await pgClient.query('DELETE FROM daily_network_retrieval_stats') + await pgClient.query('DELETE FROM daily_alternative_provider_retrieval_stats') // Run all tests inside a transaction to ensure `now()` always returns the same value // See https://dba.stackexchange.com/a/63549/125312 @@ -1174,17 +1174,17 @@ describe('public-stats', () => { it('creates or updates the row for today', async () => { /** @type {Measurement[]} */ const allMeasurements = [ - { ...VALID_MEASUREMENT, networkRetrievalResult: 'OK' }, - { ...VALID_MEASUREMENT, networkRetrievalResult: 'OK' }, + { ...VALID_MEASUREMENT, alternativeProviderRetrievalResult: 'OK' }, + { ...VALID_MEASUREMENT, alternativeProviderRetrievalResult: 'OK' }, - { ...VALID_MEASUREMENT, networkRetrievalResult: 'TIMEOUT' }, - { ...VALID_MEASUREMENT, networkRetrievalResult: 'CAR_TOO_LARGE' }, - { ...VALID_MEASUREMENT, networkRetrievalResult: 'IPNI_ERROR_FETCH' } + { ...VALID_MEASUREMENT, alternativeProviderRetrievalResult: 'TIMEOUT' }, + { ...VALID_MEASUREMENT, alternativeProviderRetrievalResult: 'CAR_TOO_LARGE' }, + { ...VALID_MEASUREMENT, alternativeProviderRetrievalResult: 'IPNI_ERROR_FETCH' } ] const committees = buildEvaluatedCommitteesFromMeasurements(allMeasurements) const { rows: created } = await pgClient.query( - 'SELECT * FROM daily_network_retrieval_stats' + 'SELECT * FROM daily_alternative_provider_retrieval_stats' ) assert.deepStrictEqual(created, []) await updateDailyNetworkRetrievalStats( @@ -1196,7 +1196,7 @@ describe('public-stats', () => { day::TEXT, total, successful - FROM daily_network_retrieval_stats`) + FROM daily_alternative_provider_retrieval_stats`) assert.deepStrictEqual(rows, [ { day: today, total: 5, successful: 2 } diff --git a/test/retrieval-stats.test.js b/test/retrieval-stats.test.js index 55c442d0..6af4d84d 100644 --- a/test/retrieval-stats.test.js +++ b/test/retrieval-stats.test.js @@ -330,11 +330,11 @@ describe('retrieval statistics', () => { const measurements = [ { ...VALID_MEASUREMENT, - networkRetrievalResult: 'OK' + alternativeProviderRetrievalResult: 'OK' }, { ...VALID_MEASUREMENT, - networkRetrievalResult: 'HTTP_500' + alternativeProviderRetrievalResult: 'HTTP_500' } ] From a9ba7fd53660473971e33f21c9c312f2b92ca004 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 19:01:50 +0200 Subject: [PATCH 10/16] Build alternative provider RSR --- lib/provider-retrieval-result-stats.js | 7 +++++-- lib/public-stats.js | 21 ++++++--------------- lib/retrieval-stats.js | 8 ++++---- test/public-stats.test.js | 13 ++++++++----- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/lib/provider-retrieval-result-stats.js b/lib/provider-retrieval-result-stats.js index b2659de2..8f31eb11 100644 --- a/lib/provider-retrieval-result-stats.js +++ b/lib/provider-retrieval-result-stats.js @@ -16,7 +16,7 @@ const withPgClient = fn => async ({ createPgClient, ...args }) => { } export const build = committees => { - /** @type {Map} */ + /** @type {Map} */ const providerRetrievalResultStats = new Map() for (const c of committees) { // IMPORTANT: include minority results in the calculation @@ -25,7 +25,7 @@ export const build = committees => { if (m.retrievalResult.match(/^IPNI_ERROR_5\d\d$/)) continue const minerId = m.minerId - const retrievalStats = providerRetrievalResultStats.get(minerId) ?? { total: 0, successful: 0, successfulHttp: 0, successfulHttpHead: 0 } + const retrievalStats = providerRetrievalResultStats.get(minerId) ?? { total: 0, successful: 0, successfulHttp: 0, successfulHttpHead: 0, successfulAltProvider: 0 } retrievalStats.total++ if (m.retrievalResult === 'OK') { retrievalStats.successful++ @@ -36,6 +36,9 @@ export const build = committees => { } } } + + if (m.alternativeProviderRetrievalResult === 'OK') retrievalStats.successfulAltProvider++ + providerRetrievalResultStats.set(minerId, retrievalStats) } } diff --git a/lib/public-stats.js b/lib/public-stats.js index 80c5caee..c67dd41a 100644 --- a/lib/public-stats.js +++ b/lib/public-stats.js @@ -23,6 +23,7 @@ export const updatePublicStats = async ({ createPgClient, committees, allMeasure try { for (const [minerId, retrievalResultStats] of stats.entries()) { await updateRetrievalStats(pgClient, minerId, retrievalResultStats) + await updateDailyAlternativeProviderRetrievalStats(pgClient, retrievalResultStats) } await updateIndexerQueryStats(pgClient, committees) await updateDailyDealsStats(pgClient, committees, findDealClients) @@ -30,7 +31,6 @@ export const updatePublicStats = async ({ createPgClient, committees, allMeasure await updateRetrievalTimings(pgClient, committees) await updateDailyClientRetrievalStats(pgClient, committees, findDealClients) await updateDailyAllocatorRetrievalStats(pgClient, committees, findDealAllocators) - await updateDailyNetworkRetrievalStats(pgClient, committees) } finally { await pgClient.end() } @@ -413,21 +413,12 @@ function buildPerPartyStats (committees, perDealParty, partyName) { * @param {pg.Client} pgClient * @param {object} stats * @param {number} stats.total - * @param {number} stats.successful + * @param {number} stats.successfulAltProvider */ -export const updateDailyNetworkRetrievalStats = async (pgClient, committees) => { - let total = 0 - let successful = 0 - for (const c of committees) { - for (const m of c.measurements) { - if (m.networkRetrievalResult === 'OK') successful++ - total++ - } - } - - debug('Updating public daily network wide retrieval stats: total += %s successful += %s', total, successful) +export const updateDailyAlternativeProviderRetrievalStats = async (pgClient, { total, successfulAltProvider }) => { + debug('Updating public daily alternative provider retrieval stats: total += %s successful += %s', total, successfulAltProvider) await pgClient.query(` - INSERT INTO daily_network_retrieval_stats + INSERT INTO daily_alternative_provider_retrieval_stats (day, total, successful) VALUES (now(), $1, $2) @@ -436,6 +427,6 @@ export const updateDailyNetworkRetrievalStats = async (pgClient, committees) => successful = daily_network_retrieval_stats.successful + $2 `, [ total, - successful + successfulAltProvider ]) } diff --git a/lib/retrieval-stats.js b/lib/retrieval-stats.js index c91d8898..8e77544d 100644 --- a/lib/retrieval-stats.js +++ b/lib/retrieval-stats.js @@ -60,7 +60,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { const sizeValues = [] let httpSuccesses = 0 let indexerServerErrorCount = 0 - let networkRetrievalSuccesses = 0 + let alternativeProviderRetrievalSuccess = 0 for (const m of measurements) { // `retrievalResult` should be always set by lib/preprocess.js, so we should never encounter @@ -107,7 +107,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { // A successful HTTP response is a response with result breakdown set to OK and the protocol being used is set to HTTP. if (m.retrievalResult === 'OK' && m.protocol === 'http') { httpSuccesses++ } - if (m.alternativeProviderRetrievalResult === 'OK') { networkRetrievalSuccesses++ } + if (m.alternativeProviderRetrievalResult === 'OK') { alternativeProviderRetrievalSuccess++ } if (m.retrievalResult.match(/^IPNI_ERROR_5\d\d$/)) { indexerServerErrorCount++ @@ -117,7 +117,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { const totalForRSR = totalCount - indexerServerErrorCount const successRate = totalForRSR ? resultBreakdown.OK / totalForRSR : 0 const successRateHttp = totalForRSR ? httpSuccesses / totalForRSR : 0 - const networkRSR = totalForRSR ? networkRetrievalSuccesses / totalForRSR : 0 + const altProviderRSR = totalForRSR ? alternativeProviderRetrievalSuccess / totalForRSR : 0 telemetryPoint.intField('total_for_success_rates', totalForRSR) telemetryPoint.intField('unique_tasks', uniqueTasksCount) telemetryPoint.floatField('success_rate', successRate) @@ -126,7 +126,7 @@ export const buildRetrievalStats = (measurements, telemetryPoint) => { telemetryPoint.intField('inet_groups', inetGroups.size) telemetryPoint.intField('measurements', totalCount) telemetryPoint.intField('download_bandwidth', downloadBandwidth) - telemetryPoint.floatField('network_success_rate', networkRSR) + telemetryPoint.floatField('alternative_provider_success_rate', altProviderRSR) addHistogramToPoint(telemetryPoint, ttfbValues, 'ttfb_') addHistogramToPoint(telemetryPoint, durationValues, 'duration_') diff --git a/test/public-stats.test.js b/test/public-stats.test.js index f20eef52..e5050810 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -4,7 +4,7 @@ import pg from 'pg' import { DATABASE_URL } from '../lib/config.js' import { migrateWithPgClient } from '../lib/migrate.js' import { buildEvaluatedCommitteesFromMeasurements, VALID_MEASUREMENT } from './helpers/test-data.js' -import { updateDailyAllocatorRetrievalStats, updateDailyClientRetrievalStats, updateDailyNetworkRetrievalStats, updatePublicStats } from '../lib/public-stats.js' +import { updateDailyAllocatorRetrievalStats, updateDailyClientRetrievalStats, updatePublicStats } from '../lib/public-stats.js' import { beforeEach } from 'mocha' import { groupMeasurementsToCommittees } from '../lib/committee.js' @@ -1187,10 +1187,13 @@ describe('public-stats', () => { 'SELECT * FROM daily_alternative_provider_retrieval_stats' ) assert.deepStrictEqual(created, []) - await updateDailyNetworkRetrievalStats( - pgClient, - committees - ) + await updatePublicStats({ + createPgClient, + committees, + allMeasurements, + findDealClients: (_minerId, _cid) => ['f0client'], + findDealAllocators: (_minerId, _cid) => ['f0allocator'] + }) const { rows } = await pgClient.query( `SELECT day::TEXT, From 4405334f6130b8210a53288b469b8734d5acfe31 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 19:12:40 +0200 Subject: [PATCH 11/16] Fix failing tests --- lib/public-stats.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/public-stats.js b/lib/public-stats.js index c67dd41a..2aa91f53 100644 --- a/lib/public-stats.js +++ b/lib/public-stats.js @@ -423,8 +423,8 @@ export const updateDailyAlternativeProviderRetrievalStats = async (pgClient, { t VALUES (now(), $1, $2) ON CONFLICT(day) DO UPDATE SET - total = daily_network_retrieval_stats.total + $1, - successful = daily_network_retrieval_stats.successful + $2 + total = daily_alternative_provider_retrieval_stats.total + $1, + successful = daily_alternative_provider_retrieval_stats.successful + $2 `, [ total, successfulAltProvider From ed53bb68501ad142a201915ab8fda34dae02435d Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 19:19:00 +0200 Subject: [PATCH 12/16] Fix failing tests --- test/provider-retrieval-result-stats.test.js | 8 ++++---- test/retrieval-stats.test.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/provider-retrieval-result-stats.test.js b/test/provider-retrieval-result-stats.test.js index 302b2bbd..fb6958ba 100644 --- a/test/provider-retrieval-result-stats.test.js +++ b/test/provider-retrieval-result-stats.test.js @@ -63,8 +63,8 @@ describe('Provider Retrieval Result Stats', () => { } ]) assert.deepStrictEqual(stats, new Map([ - ['0', { total: 2, successful: 2, successfulHttp: 1, successfulHttpHead: 1 }], - ['1', { total: 2, successful: 0, successfulHttp: 0, successfulHttpHead: 0 }] + ['0', { total: 2, successful: 2, successfulHttp: 1, successfulHttpHead: 1, successfulAltProvider: 0 }], + ['1', { total: 2, successful: 0, successfulHttp: 0, successfulHttpHead: 0, successfulAltProvider: 0 }] ])) }) }) @@ -178,8 +178,8 @@ describe('Provider Retrieval Result Stats', () => { contract_address: ieContractAddress, measurement_batches: round.measurementBatches, provider_retrieval_result_stats: { - 0: { successful: 2, total: 2, successfulHttp: 1, successfulHttpHead: 1 }, - 1: { successful: 0, total: 2, successfulHttp: 0, successfulHttpHead: 0 } + 0: { successful: 2, total: 2, successfulHttp: 1, successfulHttpHead: 1, successfulAltProvider: 0 }, + 1: { successful: 0, total: 2, successfulHttp: 0, successfulHttpHead: 0, successfulAltProvider: 0 } }, round_details: 'baguqeerawg5jfpiy2g5xp5d422uwa3mpyzkmiguoeecesds7q65mn2hdoa4q', round_index: String(round.index), diff --git a/test/retrieval-stats.test.js b/test/retrieval-stats.test.js index 6af4d84d..564b7f59 100644 --- a/test/retrieval-stats.test.js +++ b/test/retrieval-stats.test.js @@ -325,7 +325,7 @@ describe('retrieval statistics', () => { assertPointFieldValue(point, 'success_rate_http', '0.25') }) - it('records network retrieval success rate', async () => { + it('records alternative provider retrieval success rate', async () => { /** @type {Measurement[]} */ const measurements = [ { @@ -342,7 +342,7 @@ describe('retrieval statistics', () => { buildRetrievalStats(measurements, point) debug('stats', point.fields) - assertPointFieldValue(point, 'network_success_rate', '0.5') + assertPointFieldValue(point, 'alternative_provider_success_rate', '0.5') }) }) From e1ae2630ff70bc728a564459f9eff890a2c2f76f Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 19:21:25 +0200 Subject: [PATCH 13/16] Rename test --- test/public-stats.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/public-stats.test.js b/test/public-stats.test.js index e5050810..aaf2ea5f 100644 --- a/test/public-stats.test.js +++ b/test/public-stats.test.js @@ -1170,7 +1170,7 @@ describe('public-stats', () => { ]) }) - describe('updateDailyNetworkRetrievalStats ', () => { + describe('daily_alternative_provider_retrieval_stats ', () => { it('creates or updates the row for today', async () => { /** @type {Measurement[]} */ const allMeasurements = [ From 71f8c23dcc9caba52cbf4ba0313aaf5669499f17 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 15 Apr 2025 19:26:16 +0200 Subject: [PATCH 14/16] Parse alternativeProviderCheck endAt --- lib/preprocess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index f255b36f..bce624e6 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -46,7 +46,7 @@ export class Measurement { statusCode: m.alternative_provider_check_status_code, timeout: m.alternative_provider_check_timeout, carTooLarge: m.alternative_provider_check_car_too_large, - endAt: m.alternative_provider_check_end_at, + endAt: parseDateTime(m.alternative_provider_check_end_at), protocol: m.alternative_provider_check_protocol } } From 249ed97a32a80af2d6d662109550a32f5e39c0b8 Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Mon, 28 Apr 2025 12:34:44 +0200 Subject: [PATCH 15/16] Add provider id --- lib/preprocess.js | 3 ++- lib/typings.d.ts | 1 + test/helpers/test-data.js | 3 ++- test/preprocess.js | 9 ++++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index bce624e6..25d2e26c 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -47,7 +47,8 @@ export class Measurement { timeout: m.alternative_provider_check_timeout, carTooLarge: m.alternative_provider_check_car_too_large, endAt: parseDateTime(m.alternative_provider_check_end_at), - protocol: m.alternative_provider_check_protocol + protocol: m.alternative_provider_check_protocol, + providerId: pointerize(m.alternative_provider_check_provider_id) } } } diff --git a/lib/typings.d.ts b/lib/typings.d.ts index abaa3849..534cdd19 100644 --- a/lib/typings.d.ts +++ b/lib/typings.d.ts @@ -105,6 +105,7 @@ export interface RawMeasurement { alternative_provider_check_car_too_large: boolean; alternative_provider_check_end_at: string; alternative_provider_check_protocol: string; + alternative_provider_check_provider_id: string; } export type CreatePgClient = () => Promise; diff --git a/test/helpers/test-data.js b/test/helpers/test-data.js index 318e498b..1449f7ed 100644 --- a/test/helpers/test-data.js +++ b/test/helpers/test-data.js @@ -50,7 +50,8 @@ export const VALID_MEASUREMENT = { timeout: false, carTooLarge: false, endAt: null, - protocol: 'http' + protocol: 'http', + providerId: 'ALTPROVIDERID' } } diff --git a/test/preprocess.js b/test/preprocess.js index 9a412a97..74f85940 100644 --- a/test/preprocess.js +++ b/test/preprocess.js @@ -463,7 +463,8 @@ describe('getAlternativeProviderRetrievalResult', () => { alternative_provider_check_timeout: false, alternative_provider_check_status_code: 200, alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http' + alternative_provider_check_protocol: 'http', + alternative_provider_check_provider_id: 'ALTPROVIDERID' }) assert.strictEqual(result, 'TIMEOUT') }) @@ -484,7 +485,8 @@ describe('getAlternativeProviderRetrievalResult', () => { alternative_provider_check_timeout: false, alternative_provider_check_status_code: 200, alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http' + alternative_provider_check_protocol: 'http', + alternative_provider_check_provider_id: 'ALTPROVIDERID' }) assert.strictEqual(result, 'OK') }) @@ -497,7 +499,8 @@ describe('getAlternativeProviderRetrievalResult', () => { alternative_provider_check_timeout: true, alternative_provider_check_status_code: 500, alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http' + alternative_provider_check_protocol: 'http', + alternative_provider_check_provider_id: 'ALTPROVIDERID' }) assert.strictEqual(result, 'TIMEOUT') }) From 2f21a880f5549a72202e9a21fb07d40156477f6e Mon Sep 17 00:00:00 2001 From: Srdjan S Date: Tue, 29 Apr 2025 14:01:36 +0200 Subject: [PATCH 16/16] Update new raw measurement schema --- lib/preprocess.js | 26 +++++++++++++------------- lib/typings.d.ts | 15 +++++++++------ test/preprocess.js | 42 ++++++++++++++++++++++++------------------ 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/lib/preprocess.js b/lib/preprocess.js index 25d2e26c..0136f2a8 100644 --- a/lib/preprocess.js +++ b/lib/preprocess.js @@ -43,12 +43,12 @@ export class Measurement { this.carChecksum = pointerize(m.car_checksum) this.carTooLarge = m.car_too_large this.alternativeProviderCheck = { - statusCode: m.alternative_provider_check_status_code, - timeout: m.alternative_provider_check_timeout, - carTooLarge: m.alternative_provider_check_car_too_large, - endAt: parseDateTime(m.alternative_provider_check_end_at), - protocol: m.alternative_provider_check_protocol, - providerId: pointerize(m.alternative_provider_check_provider_id) + statusCode: m.alternative_provider_check?.status_code, + timeout: m.alternative_provider_check?.timeout, + carTooLarge: m.alternative_provider_check?.car_too_large, + endAt: parseDateTime(m.alternative_provider_check?.end_at), + protocol: m.alternative_provider_check?.protocol, + providerId: pointerize(m.alternative_provider_check?.provider_id) } } } @@ -339,19 +339,19 @@ export const getRetrievalResult = (measurement) => { * @return {import('./typings.js').RetrievalResult} */ export const getAlternativeProviderRetrievalResult = (measurement) => { - if (measurement.indexer_result !== 'NO_VALID_ADVERTISEMENT' || !measurement.alternative_provider_check_status_code) { + if (measurement.indexer_result !== 'NO_VALID_ADVERTISEMENT' || !measurement.alternative_provider_check?.status_code) { return getRetrievalResult(measurement) } /** @type {Partial} */ const alternativeProviderMeasurement = { indexer_result: 'OK', - status_code: measurement.alternative_provider_check_status_code, - timeout: measurement.alternative_provider_check_timeout, - alternative_provider_check_status_code: measurement.alternative_provider_check_status_code, - car_too_large: measurement.alternative_provider_check_car_too_large, - end_at: measurement.alternative_provider_check_end_at, - protocol: measurement.alternative_provider_check_protocol + timeout: measurement.alternative_provider_check?.timeout, + status_code: measurement.alternative_provider_check?.status_code, + car_too_large: measurement.alternative_provider_check?.car_too_large, + end_at: measurement.alternative_provider_check?.end_at, + protocol: measurement.alternative_provider_check?.protocol, + provider_id: measurement.alternative_provider_check?.provider_id } return getRetrievalResult(alternativeProviderMeasurement) diff --git a/lib/typings.d.ts b/lib/typings.d.ts index 534cdd19..8bb97927 100644 --- a/lib/typings.d.ts +++ b/lib/typings.d.ts @@ -100,12 +100,15 @@ export interface RawMeasurement { | 'NO_VALID_ADVERTISEMENT' | 'ERROR_FETCH' | `ERROR_${number}`; - alternative_provider_check_status_code: number | undefined | null; - alternative_provider_check_timeout: boolean; - alternative_provider_check_car_too_large: boolean; - alternative_provider_check_end_at: string; - alternative_provider_check_protocol: string; - alternative_provider_check_provider_id: string; + + alternative_provider_check: { + status_code: number | undefined | null; + timeout: boolean; + car_too_large: boolean; + end_at: string; + protocol: string; + provider_id: string; + }; } export type CreatePgClient = () => Promise; diff --git a/test/preprocess.js b/test/preprocess.js index 74f85940..3485754e 100644 --- a/test/preprocess.js +++ b/test/preprocess.js @@ -459,12 +459,14 @@ describe('getAlternativeProviderRetrievalResult', () => { const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, timeout: true, - alternative_provider_check_car_too_large: false, - alternative_provider_check_timeout: false, - alternative_provider_check_status_code: 200, - alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http', - alternative_provider_check_provider_id: 'ALTPROVIDERID' + alternative_provider_check: { + car_too_large: false, + timeout: false, + status_code: 200, + end_at: '2023-11-01T09:42:03.246Z', + protocol: 'http', + provider_id: 'ALTPROVIDERID' + } }) assert.strictEqual(result, 'TIMEOUT') }) @@ -481,12 +483,14 @@ describe('getAlternativeProviderRetrievalResult', () => { const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, indexer_result: 'NO_VALID_ADVERTISEMENT', - alternative_provider_check_car_too_large: false, - alternative_provider_check_timeout: false, - alternative_provider_check_status_code: 200, - alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http', - alternative_provider_check_provider_id: 'ALTPROVIDERID' + alternative_provider_check: { + car_too_large: false, + timeout: false, + status_code: 200, + end_at: '2023-11-01T09:42:03.246Z', + protocol: 'http', + provider_id: 'ALTPROVIDERID' + } }) assert.strictEqual(result, 'OK') }) @@ -495,12 +499,14 @@ describe('getAlternativeProviderRetrievalResult', () => { const result = getAlternativeProviderRetrievalResult({ ...SUCCESSFUL_RETRIEVAL, indexer_result: 'NO_VALID_ADVERTISEMENT', - alternative_provider_check_car_too_large: false, - alternative_provider_check_timeout: true, - alternative_provider_check_status_code: 500, - alternative_provider_check_end_at: '2023-11-01T09:42:03.246Z', - alternative_provider_check_protocol: 'http', - alternative_provider_check_provider_id: 'ALTPROVIDERID' + alternative_provider_check: { + car_too_large: false, + timeout: true, + status_code: 500, + end_at: '2023-11-01T09:42:03.246Z', + protocol: 'http', + provider_id: 'ALTPROVIDERID' + } }) assert.strictEqual(result, 'TIMEOUT') })