Skip to content

Commit 71f157d

Browse files
SgtPookiBigLep
andauthored
fix: IPNI validation confirms provider in indexer response (#231)
* fix: validateIpniAdvertisement checks provider previously, validateIpniAdvertisement did not validate that the ipni advertisement existed for the given provider. Now, we validate that the response includes the expected provider, and allow consumers to pass extra providers (to support future multiple provider uploads) * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * fix: fine-tune logic, remove dead branches * fix: allow ipniIndexer override, default to filecoinpin.contact * fix: use only current provider serviceURL * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * chore: more logic cleanup * fix: display received + expected multiaddrs * refactor: inline simple maps and filters * chore: more code cleanup * fix: PDP definition * chore: cleanup validateIpni options set in executeUpload * fix: last error message * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/test/unit/validate-ipni-advertisement.test.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/test/unit/validate-ipni-advertisement.test.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/test/unit/validate-ipni-advertisement.test.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/test/unit/validate-ipni-advertisement.test.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * fix: remove expectedProviderMultiaddrs * refactor: validateIPNIadvertisement -> waitForIpniProviderResults * fix: use set operations, finish move to waitForIpniProviderResults * fix: update terminology, ipniAdvertisement -> ipni provider results * fix: include Set operations in typescript * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * Update src/core/utils/validate-ipni-advertisement.ts Co-authored-by: Steve Loeppky <[email protected]> * chore: lint fix * test: fix tests after error msg change --------- Co-authored-by: Steve Loeppky <[email protected]>
1 parent 70e780f commit 71f157d

File tree

7 files changed

+593
-89
lines changed

7 files changed

+593
-89
lines changed

src/common/upload-flow.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ export async function performUpload(
267267

268268
let pieceCid: PieceCID | undefined
269269
function getIpniAdvertisementMsg(attemptCount: number): string {
270-
return `Checking for IPNI advertisement (check #${attemptCount})`
270+
return `Checking for IPNI provider records (check #${attemptCount})`
271271
}
272272

273273
const uploadResult = await executeUpload(synapseService, carData, rootCid, {
@@ -321,14 +321,14 @@ export async function performUpload(
321321
break
322322
}
323323

324-
case 'ipniAdvertisement.retryUpdate': {
324+
case 'ipniProviderResults.retryUpdate': {
325325
const attemptCount = event.data.retryCount === 0 ? 1 : event.data.retryCount + 1
326326
flow.addOperation('ipni', getIpniAdvertisementMsg(attemptCount))
327327
break
328328
}
329-
case 'ipniAdvertisement.complete': {
329+
case 'ipniProviderResults.complete': {
330330
// complete event is only emitted when result === true (success)
331-
flow.completeOperation('ipni', 'IPNI advertisement successful. IPFS retrieval possible.', {
331+
flow.completeOperation('ipni', 'IPNI provider records found. IPFS retrieval possible.', {
332332
type: 'success',
333333
details: {
334334
title: 'IPFS Retrieval URLs',
@@ -341,12 +341,12 @@ export async function performUpload(
341341
})
342342
break
343343
}
344-
case 'ipniAdvertisement.failed': {
345-
flow.completeOperation('ipni', 'IPNI advertisement failed.', {
344+
case 'ipniProviderResults.failed': {
345+
flow.completeOperation('ipni', 'IPNI provider records not found.', {
346346
type: 'warning',
347347
details: {
348348
title: 'IPFS retrieval is not possible yet.',
349-
content: [pc.gray(`IPNI advertisement does not exist at http://filecoinpin.contact/cid/${rootCid}`)],
349+
content: [pc.gray(`IPNI provider records for this SP does not exist for the provided root CID`)],
350350
},
351351
})
352352
break

src/core/upload/index.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import {
1313
import { isSessionKeyMode, type SynapseService } from '../synapse/index.js'
1414
import type { ProgressEvent, ProgressEventHandler } from '../utils/types.js'
1515
import {
16-
type ValidateIPNIAdvertisementOptions,
1716
type ValidateIPNIProgressEvents,
18-
validateIPNIAdvertisement,
17+
type WaitForIpniProviderResultsOptions,
18+
waitForIpniProviderResults,
1919
} from '../utils/validate-ipni-advertisement.js'
2020
import { type SynapseUploadResult, type UploadProgressEvents, uploadToSynapse } from './synapse.js'
2121

@@ -195,7 +195,7 @@ export interface UploadExecutionOptions {
195195
* @default: true
196196
*/
197197
enabled?: boolean
198-
} & Omit<ValidateIPNIAdvertisementOptions, 'onProgress'>
198+
} & Omit<WaitForIpniProviderResultsOptions, 'onProgress'>
199199
}
200200

201201
export interface UploadExecutionResult extends SynapseUploadResult {
@@ -230,13 +230,31 @@ export async function executeUpload(
230230
case 'onPieceAdded': {
231231
// Begin IPNI validation as soon as the piece is added and parked in the data set
232232
if (options.ipniValidation?.enabled !== false && ipniValidationPromise == null) {
233-
const { enabled: _enabled, ...rest } = options.ipniValidation ?? {}
234-
ipniValidationPromise = validateIPNIAdvertisement(rootCid, {
235-
...rest,
233+
const { enabled: _enabled, expectedProviders, ...restOptions } = options.ipniValidation ?? {}
234+
235+
// Build validation options
236+
const validationOptions: WaitForIpniProviderResultsOptions = {
237+
...restOptions,
236238
logger,
237-
...(options?.onProgress != null ? { onProgress: options.onProgress } : {}),
238-
}).catch((error) => {
239-
logger.warn({ error }, 'IPNI advertisement validation promise rejected')
239+
}
240+
241+
// Forward progress events to caller if they provided a handler
242+
if (options?.onProgress != null) {
243+
validationOptions.onProgress = options.onProgress
244+
}
245+
246+
// Determine which providers to expect in IPNI
247+
// Priority: user-provided expectedProviders > current provider > none (generic validation)
248+
// Note: If expectedProviders is explicitly [], we respect that (no provider expectations)
249+
if (expectedProviders != null) {
250+
validationOptions.expectedProviders = expectedProviders
251+
} else if (synapseService.providerInfo != null) {
252+
validationOptions.expectedProviders = [synapseService.providerInfo]
253+
}
254+
255+
// Start validation (runs in parallel with other operations)
256+
ipniValidationPromise = waitForIpniProviderResults(rootCid, validationOptions).catch((error) => {
257+
logger.warn({ error }, 'IPNI provider results check was rejected')
240258
return false
241259
})
242260
}
@@ -270,7 +288,7 @@ export async function executeUpload(
270288
try {
271289
ipniValidated = await ipniValidationPromise
272290
} catch (error) {
273-
logger.error({ error }, 'Could not validate IPNI advertisement')
291+
logger.error({ error }, 'Could not validate IPNI provider records')
274292
ipniValidated = false
275293
}
276294
}

0 commit comments

Comments
 (0)