Skip to content

Commit e2a458b

Browse files
authored
Add HTTP HEAD success count. CheckerNetwork/spark-checker#104 (#475)
* Add HTTP HEAD success count. CheckerNetwork/spark-checker#104 * add passing validation test * fix lint * fix migration conflict
1 parent c3cc9c7 commit e2a458b

10 files changed

+55
-22
lines changed

lib/preprocess.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export class Measurement {
3535
this.first_byte_at = parseDateTime(m.first_byte_at)
3636
this.end_at = parseDateTime(m.end_at)
3737
this.status_code = m.status_code
38+
this.head_status_code = m.head_status_code
3839
this.timeout = m.timeout
3940
this.indexerResult = pointerize(m.indexer_result)
4041
this.stationId = pointerize(m.station_id)
@@ -266,6 +267,8 @@ export const assertValidMeasurement = measurement => {
266267
assert(measurement.end_at >= measurement.start_at, 'end_at must be greater than or equal to start_at')
267268
assert(measurement.end_at >= measurement.first_byte_at, 'end_at must be greater than or equal to first_byte_at')
268269
assert(measurement.first_byte_at >= measurement.start_at, 'first_byte_at must be greater than or equal to start_at')
270+
271+
assert.strictEqual(typeof measurement.head_status_code, 'number', '`head_status_code` must be a number')
269272
}
270273
}
271274

lib/provider-retrieval-result-stats.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,22 @@ const withPgClient = fn => async ({ createPgClient, ...args }) => {
1616
}
1717

1818
export const build = committees => {
19-
/** @type {Map<string, {total: number, successful: number, successfulHttp:number}>} */
19+
/** @type {Map<string, {total: number, successful: number, successfulHttp:number, successfulHttpHead: number}>} */
2020
const providerRetrievalResultStats = new Map()
2121
for (const c of committees) {
2222
// IMPORTANT: include minority results in the calculation
2323
for (const m of c.measurements) {
2424
const minerId = m.minerId
25-
const retrievalStats = providerRetrievalResultStats.get(minerId) ?? { total: 0, successful: 0, successfulHttp: 0 }
25+
const retrievalStats = providerRetrievalResultStats.get(minerId) ?? { total: 0, successful: 0, successfulHttp: 0, successfulHttpHead: 0 }
2626
retrievalStats.total++
2727
if (m.retrievalResult === 'OK') {
2828
retrievalStats.successful++
29-
if (m.protocol && m.protocol === 'http') { retrievalStats.successfulHttp++ }
29+
if (m.protocol && m.protocol === 'http') {
30+
retrievalStats.successfulHttp++
31+
if (typeof m.head_status_code === 'number' && m.head_status_code >= 200 && m.head_status_code < 300) {
32+
retrievalStats.successfulHttpHead++
33+
}
34+
}
3035
}
3136
providerRetrievalResultStats.set(minerId, retrievalStats)
3237
}

lib/public-stats.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,26 @@ export const updatePublicStats = async ({ createPgClient, committees, allMeasure
4040
* @param {number} stats.total
4141
* @param {number} stats.successful
4242
* @param {number} stats.successfulHttp
43+
* @param {number} stats.successfulHttpHead
4344
*/
44-
const updateRetrievalStats = async (pgClient, minerId, { total, successful, successfulHttp }) => {
45-
debug('Updating public retrieval stats for miner %s: total += %s successful += %s, successful_http += %s', minerId, total, successful, successfulHttp)
45+
const updateRetrievalStats = async (pgClient, minerId, { total, successful, successfulHttp, successfulHttpHead }) => {
46+
debug('Updating public retrieval stats for miner %s: total += %s successful += %s, successful_http += %s, successful_http_head += %s', minerId, total, successful, successfulHttp, successfulHttpHead)
4647
await pgClient.query(`
4748
INSERT INTO retrieval_stats
48-
(day, miner_id, total, successful, successful_http)
49+
(day, miner_id, total, successful, successful_http, successful_http_head)
4950
VALUES
50-
(now(), $1, $2, $3, $4)
51+
(now(), $1, $2, $3, $4, $5)
5152
ON CONFLICT(day, miner_id) DO UPDATE SET
5253
total = retrieval_stats.total + $2,
5354
successful = retrieval_stats.successful + $3,
54-
successful_http = retrieval_stats.successful_http + $4
55+
successful_http = retrieval_stats.successful_http + $4,
56+
successful_http_head = retrieval_stats.successful_http_head + $5
5557
`, [
5658
minerId,
5759
total,
5860
successful,
59-
successfulHttp
61+
successfulHttp,
62+
successfulHttpHead
6063
])
6164
}
6265

lib/typings.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export interface RawMeasurement {
8787
finished_at: string;
8888

8989
status_code: number | undefined | null;
90+
head_status_code: number | undefined | null;
9091
timeout: boolean;
9192
byte_length: number;
9293
car_too_large: boolean;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE retrieval_stats ADD COLUMN successful_http_head INT;

test/evaluate.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ describe('evaluate', async function () {
9898
total: 1,
9999
successful: 1,
100100
// None of the measurements use http
101-
successful_http: 0
101+
successful_http: 0,
102+
successful_http_head: 0
102103
}])
103104
})
104105
it('handles empty rounds', async () => {

test/helpers/test-data.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const VALID_MEASUREMENT = {
2727
stationId: VALID_STATION_ID,
2828
inet_group: VALID_INET_GROUP,
2929
status_code: 200,
30+
head_status_code: 200,
3031
// TODO: these fields are not part of the Measurement object yet
3132
// timeout: false,
3233
// car_too_large: false,

test/preprocess.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,22 @@ describe('assertValidMeasurement', () => {
310310
/field `indexerResult` must be set/
311311
)
312312
})
313+
it('rejects measurements with OK retrieval result but head_status_code is not a number', () => {
314+
assert.throws(
315+
() => assertValidMeasurement({
316+
...VALID_MEASUREMENT,
317+
head_status_code: null
318+
}),
319+
/`head_status_code` must be a number/
320+
)
321+
assert.throws(
322+
() => assertValidMeasurement({
323+
...VALID_MEASUREMENT,
324+
head_status_code: /** @type {any} */ ('200')
325+
}),
326+
/`head_status_code` must be a number/
327+
)
328+
})
313329

314330
it('should throw an error for invalid start_at', () => {
315331
const measurement = {

test/provider-retrieval-result-stats.test.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ describe('Provider Retrieval Result Stats', () => {
3838
{
3939
minerId: '0',
4040
retrievalResult: 'OK',
41-
protocol: 'http'
41+
protocol: 'http',
42+
head_status_code: 200
4243
},
4344
{
4445
minerId: '1',
@@ -62,8 +63,8 @@ describe('Provider Retrieval Result Stats', () => {
6263
}
6364
])
6465
assert.deepStrictEqual(stats, new Map([
65-
['0', { total: 2, successful: 2, successfulHttp: 1 }],
66-
['1', { total: 2, successful: 0, successfulHttp: 0 }]
66+
['0', { total: 2, successful: 2, successfulHttp: 1, successfulHttpHead: 1 }],
67+
['1', { total: 2, successful: 0, successfulHttp: 0, successfulHttpHead: 0 }]
6768
]))
6869
})
6970
})
@@ -142,7 +143,8 @@ describe('Provider Retrieval Result Stats', () => {
142143
{
143144
minerId: '0',
144145
retrievalResult: 'OK',
145-
protocol: 'http'
146+
protocol: 'http',
147+
head_status_code: 200
146148
},
147149
{
148150
minerId: '1',
@@ -176,8 +178,8 @@ describe('Provider Retrieval Result Stats', () => {
176178
contract_address: ieContractAddress,
177179
measurement_batches: round.measurementBatches,
178180
provider_retrieval_result_stats: {
179-
0: { successful: 2, total: 2, successfulHttp: 1 },
180-
1: { successful: 0, total: 2, successfulHttp: 0 }
181+
0: { successful: 2, total: 2, successfulHttp: 1, successfulHttpHead: 1 },
182+
1: { successful: 0, total: 2, successfulHttp: 0, successfulHttpHead: 0 }
181183
},
182184
round_details: 'baguqeerawg5jfpiy2g5xp5d422uwa3mpyzkmiguoeecesds7q65mn2hdoa4q',
183185
round_index: String(round.index),

test/public-stats.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe('public-stats', () => {
9090
it('calculates successful http retrievals correctly', async () => {
9191
/** @type {Measurement[]} */
9292
const honestMeasurements = [
93-
{ ...VALID_MEASUREMENT, protocol: 'http', retrievalResult: 'OK' },
93+
{ ...VALID_MEASUREMENT, protocol: 'http', retrievalResult: 'OK', head_status_code: 200 },
9494
{ ...VALID_MEASUREMENT, protocol: 'graphsync', retrievalResult: 'OK' },
9595
{ ...VALID_MEASUREMENT, protocol: 'http', retrievalResult: 'HTTP_500' },
9696
{ ...VALID_MEASUREMENT, protocol: 'graphsync', retrievalResult: 'LASSIE_500' }
@@ -106,14 +106,14 @@ describe('public-stats', () => {
106106
})
107107

108108
const { rows: created } = await pgClient.query(
109-
'SELECT day::TEXT, total, successful, successful_http FROM retrieval_stats'
109+
'SELECT day::TEXT, total, successful, successful_http, successful_http_head FROM retrieval_stats'
110110
)
111111
assert.deepStrictEqual(created, [
112-
{ day: today, total: 4, successful: 2, successful_http: 1 }
112+
{ day: today, total: 4, successful: 2, successful_http: 1, successful_http_head: 1 }
113113
])
114114

115115
// Let's add another successful http retrieval to make sure the updating process works as expected
116-
honestMeasurements.push({ ...VALID_MEASUREMENT, retrievalResult: 'OK', protocol: 'http' })
116+
honestMeasurements.push({ ...VALID_MEASUREMENT, retrievalResult: 'OK', protocol: 'http', head_status_code: 200 })
117117
committees = buildEvaluatedCommitteesFromMeasurements(honestMeasurements)
118118
await updatePublicStats({
119119
createPgClient,
@@ -123,10 +123,10 @@ describe('public-stats', () => {
123123
})
124124

125125
const { rows: updated } = await pgClient.query(
126-
'SELECT day::TEXT, total, successful, successful_http FROM retrieval_stats'
126+
'SELECT day::TEXT, total, successful, successful_http, successful_http_head FROM retrieval_stats'
127127
)
128128
assert.deepStrictEqual(updated, [
129-
{ day: today, total: 4 + 5, successful: 2 + 3, successful_http: 1 + 2 }
129+
{ day: today, total: 4 + 5, successful: 2 + 3, successful_http: 1 + 2, successful_http_head: 1 + 2 }
130130
])
131131
})
132132

0 commit comments

Comments
 (0)