Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: record RSR per miner id #178

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions lib/public-stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@ const debug = createDebug('spark:public-stats')
* @param {import('./preprocess').Measurement[]} args.honestMeasurements
*/
export const updatePublicStats = async ({ createPgClient, honestMeasurements }) => {
const retrievalStats = { total: 0, successful: 0 }
/** @type {Map<string, {{total: number, successful: number}}>} */
const minerRetrievalStats = new Map()
const participants = new Set()
for (const m of honestMeasurements) {
const minerId = m.minerId
const retrievalStats = minerRetrievalStats.get(minerId) ?? { total: 0, successful: 0 }
retrievalStats.total++
if (m.retrievalResult === 'OK') retrievalStats.successful++
minerRetrievalStats.set(minerId, retrievalStats)

participants.add(m.participantAddress)
}

const pgClient = await createPgClient()
try {
await updateRetrievalStats(pgClient, retrievalStats)
for (const [minerId, retrievalStats] of minerRetrievalStats.entries()) {
await updateRetrievalStats(pgClient, minerId, retrievalStats)
}
await updateDailyParticipants(pgClient, participants)
await updateIndexerQueryStats(pgClient, honestMeasurements)
} finally {
Expand All @@ -32,21 +38,23 @@ export const updatePublicStats = async ({ createPgClient, honestMeasurements })

/**
* @param {import('pg').Client} pgClient
* @param {string} minerId
* @param {object} stats
* @param {number} stats.total
* @param {number} stats.successful
*/
const updateRetrievalStats = async (pgClient, { total, successful }) => {
debug('Updating public retrieval stats: total += %s successful += %s', total, successful)
const updateRetrievalStats = async (pgClient, minerId, { total, successful }) => {
debug('Updating public retrieval stats for miner %s: total += %s successful += %s', minerId, total, successful)
await pgClient.query(`
INSERT INTO retrieval_stats
(day, total, successful)
(day, miner_id, total, successful)
VALUES
(now(), $1, $2)
ON CONFLICT(day) DO UPDATE SET
total = retrieval_stats.total + $1,
successful = retrieval_stats.successful + $2
(now(), $1, $2, $3)
ON CONFLICT(day, miner_id) DO UPDATE SET
total = retrieval_stats.total + $2,
successful = retrieval_stats.successful + $3
`, [
minerId,
total,
successful
])
Expand Down
20 changes: 20 additions & 0 deletions migrations/005.do.miner-retrieval-stats.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ALTER TABLE retrieval_stats
ADD COLUMN miner_id TEXT;

-- We don't have miner_id for historical measurements.
-- Let's set the id to a special constant that's not a valid actor address.
UPDATE retrieval_stats SET miner_id = 'LEGACY';

-- Going forwards, all new stats must be linked to a particular miner
ALTER TABLE retrieval_stats
ALTER COLUMN miner_id SET NOT NULL;

-- Change the primary key to a composite pair (day, miner_id)
ALTER TABLE retrieval_stats
DROP CONSTRAINT retrieval_stats_pkey;

ALTER TABLE retrieval_stats
ADD PRIMARY KEY (day, miner_id);

-- Add back index on retrieval_stats
CREATE INDEX retrieval_stats_day ON retrieval_stats (day);
32 changes: 31 additions & 1 deletion test/public-stats.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('public-stats', () => {
})

describe('retrieval_stats', () => {
it('creates or updates the row for today', async () => {
it('creates or updates the row for today - one miner only', async () => {
/** @type {import('../lib/preprocess').Measurement[]} */
const honestMeasurements = [
{ ...VALID_MEASUREMENT, retrievalResult: 'OK' },
Expand All @@ -70,6 +70,36 @@ describe('public-stats', () => {
{ day: today, total: 2 + 3, successful: 1 + 1 }
])
})

it('creates or updates the row for today - multiple miners', async () => {
/** @type {import('../lib/preprocess').Measurement[]} */
const honestMeasurements = [
{ ...VALID_MEASUREMENT, minerId: 'f1first', retrievalResult: 'OK' },
{ ...VALID_MEASUREMENT, minerId: 'f1first', retrievalResult: 'TIMEOUT' },
{ ...VALID_MEASUREMENT, minerId: 'f1second', retrievalResult: 'OK' }
]
await updatePublicStats({ createPgClient, honestMeasurements })

const { rows: created } = await pgClient.query(
'SELECT day::TEXT, miner_id, total, successful FROM retrieval_stats'
)
assert.deepStrictEqual(created, [
{ day: today, miner_id: 'f1first', total: 2, successful: 1 },
{ day: today, miner_id: 'f1second', total: 1, successful: 1 }
])

honestMeasurements.push({ ...VALID_MEASUREMENT, minerId: 'f1first', retrievalResult: 'UNKNOWN_ERROR' })
honestMeasurements.push({ ...VALID_MEASUREMENT, minerId: 'f1second', retrievalResult: 'UNKNOWN_ERROR' })
await updatePublicStats({ createPgClient, honestMeasurements })

const { rows: updated } = await pgClient.query(
'SELECT day::TEXT, miner_id, total, successful FROM retrieval_stats'
)
assert.deepStrictEqual(updated, [
{ day: today, miner_id: 'f1first', total: 2 + 3, successful: 1 + 1 },
{ day: today, miner_id: 'f1second', total: 1 + 2, successful: 1 + 1 }
])
})
})

describe('daily_participants', () => {
Expand Down
Loading