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

Add per-miner RSR #265

Merged
merged 2 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Base URL: http://stats.filspark.com/

http://stats.filspark.com/miners/retrieval-success-rate/summary

- `GET /miner/:id/retrieval-success-rate/summary?from=<day>&to=<day>`

http://stats.filspark.com/miner/f0814049/retrieval-success-rate/summary

- `GET /miner/:id/deals/eligible/summary`

http://stats.filspark.com/miner/f0814049/deals/eligible/summary
Expand Down
5 changes: 4 additions & 1 deletion stats/lib/handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
fetchParticipantRewardTransfers,
fetchRetrievalSuccessRate,
fetchDealSummary,
fetchDailyRetrievalResultCodes
fetchDailyRetrievalResultCodes,
fetchDailyMinerRSRSummary
} from './stats-fetchers.js'

import { handlePlatformRoutes } from './platform-routes.js'
Expand Down Expand Up @@ -107,6 +108,8 @@ const handler = async (req, res, pgPools, SPARK_API_BASE_URL) => {
await respond(fetchMinersRSRSummary)
} else if (req.method === 'GET' && url === '/retrieval-result-codes/daily') {
await respond(fetchDailyRetrievalResultCodes)
} else if (req.method === 'GET' && segs[0] === 'miner' && segs[1] && segs[2] === 'retrieval-success-rate' && segs[3] === 'summary') {
await respond(fetchDailyMinerRSRSummary, segs[1])
} else if (req.method === 'GET' && segs[0] === 'miner' && segs[1] && segs[2] === 'deals' && segs[3] === 'eligible' && segs[4] === 'summary') {
redirectToSparkApi(req, res, SPARK_API_BASE_URL)
} else if (req.method === 'GET' && segs[0] === 'client' && segs[1] && segs[2] === 'deals' && segs[3] === 'eligible' && segs[4] === 'summary') {
Expand Down
28 changes: 28 additions & 0 deletions stats/lib/stats-fetchers.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export const fetchParticipantRewardTransfers = async (pgPools, { from, to }, add
}

/**
* Fetches the retrieval stats summary for all miners for given date range.
pyropy marked this conversation as resolved.
Show resolved Hide resolved
* @param {PgPools} pgPools
* @param {import('./typings.js').DateRangeFilter} filter
*/
Expand All @@ -223,6 +224,33 @@ export const fetchMinersRSRSummary = async (pgPools, filter) => {
return stats
}

/**
* Fetches the retrieval stats summary for a single miner for given date range.
* @param {PgPools} pgPools
* @param {import('./typings.js').DateRangeFilter} filter
* @param {string} minerId
*/
export const fetchDailyMinerRSRSummary = async (pgPools, { from, to }, minerId) => {
const { rows } = await pgPools.evaluate.query(`
SELECT day::TEXT, SUM(total) as total, SUM(successful) as successful
FROM retrieval_stats
WHERE miner_id = $1 AND day >= $2 AND day <= $3
GROUP BY day
ORDER BY day
`, [
minerId,
from,
to
])
const stats = rows.map(r => ({
day: r.day,
total: r.total,
successful: r.successful,
success_rate: r.total > 0 ? r.successful / r.total : null
}))
return stats
}

export const fetchDailyRetrievalResultCodes = async (pgPools, filter) => {
const { rows } = await pgPools.stats.query(`
SELECT day::TEXT, code, rate
Expand Down
34 changes: 34 additions & 0 deletions stats/test/handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,40 @@ describe('HTTP request handler', () => {
assert.strictEqual(res.headers.get('access-control-allow-origin'), 'http://localhost:3000')
})
})

describe('GET /miner/{id}/retrieval-success-rate/summary', () => {
it('lists daily retrieval stats summary for specified miner in given date range', async () => {
// before the range
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-09', minerId: 'f1one', total: 10, successful: 1 })
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-09', minerId: 'f1two', total: 100, successful: 20 })
// in the range
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-20', minerId: 'f1one', total: 20, successful: 1 })
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-20', minerId: 'f1two', total: 200, successful: 60 })
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-10', minerId: 'f1one', total: 10, successful: 1 })
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-10', minerId: 'f1two', total: 100, successful: 50 })
// after the range
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-21', minerId: 'f1one', total: 30, successful: 1 })
await givenRetrievalStats(pgPools.evaluate, { day: '2024-01-21', minerId: 'f1two', total: 300, successful: 60 })

const res = await fetch(
new URL(
'/miner/f1one/retrieval-success-rate/summary?from=2024-01-10&to=2024-01-20',
baseUrl
), {
redirect: 'manual'
}
)
await assertResponseStatus(res, 200)

const stats = /** @type {{ day: string, success_rate: number }[]} */(
await res.json()
)
assert.deepStrictEqual(stats, [
{ day: '2024-01-10', success_rate: 1 / 10, total: '10', successful: '1' },
{ day: '2024-01-20', success_rate: 1 / 20, total: '20', successful: '1' }
])
})
})
})

/**
Expand Down
Loading