Skip to content
This repository was archived by the owner on Jan 7, 2026. It is now read-only.

Commit ed11e3b

Browse files
Merge pull request #7 from CheckerNetwork/nhaimerl-add-index-probier-library
feat: add index provider library
2 parents f86c00c + 8d747b3 commit ed11e3b

File tree

7 files changed

+25705
-1036
lines changed

7 files changed

+25705
-1036
lines changed

deps.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
export { encodeHex } from 'https://deno.land/std@0.203.0/encoding/hex.ts'
88
export { decodeBase64 } from 'https://deno.land/std@0.203.0/encoding/base64.ts'
99
export { decode as decodeVarint } from 'https://deno.land/x/varint@v2.0.0/varint.ts'
10-
export { retry } from 'https://deno.land/std@0.203.0/async/retry.ts';
11-
1210

1311
// Deno Bundle does not support npm dependencies, we have to load them via CDN
1412
export { CarBlockIterator } from 'https://cdn.skypack.dev/@ipld/car@5.3.2/?dts'
13+
export {
14+
getIndexProviderPeerId,
15+
MINER_TO_PEERID_CONTRACT_ADDRESS,
16+
MINER_TO_PEERID_CONTRACT_ABI,
17+
} from 'https://cdn.jsdelivr.net/npm/index-provider-peer-id@1.0.1/index.js/+esm'
18+
export { ethers } from 'https://cdn.jsdelivr.net/npm/ethers@6.13.5/dist/ethers.min.js'
19+
1520
export {
1621
UnsupportedHashError,
1722
HashMismatchError,

lib/miner-info.js

Lines changed: 27 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,39 @@
1-
import { retry } from '../vendor/deno-deps.js'
21
import { RPC_URL, RPC_AUTH } from './constants.js'
2+
import {
3+
getIndexProviderPeerId as getPeerId,
4+
MINER_TO_PEERID_CONTRACT_ADDRESS,
5+
MINER_TO_PEERID_CONTRACT_ABI
6+
, ethers
7+
} from '../vendor/deno-deps.js'
38

4-
async function getChainHead ({ maxAttempts = 5 } = {}) {
5-
try {
6-
const res = await retry(() => rpc('Filecoin.ChainHead'), {
7-
// The maximum amount of attempts until failure.
8-
maxAttempts,
9-
// The initial and minimum amount of milliseconds between attempts.
10-
minTimeout: 5_000,
11-
// How much to backoff after each retry.
12-
multiplier: 1.5
13-
})
14-
return res.Cids
15-
} catch (err) {
16-
if (err.name === 'RetryError' && err.cause) {
17-
// eslint-disable-next-line no-ex-assign
18-
err = err.cause
19-
}
20-
err.message = `Cannot obtain chain head: ${err.message}`
21-
throw err
22-
}
23-
}
9+
// Initialize your ethers contract instance
10+
const fetchRequest = new ethers.FetchRequest(RPC_URL)
11+
fetchRequest.setHeader('Authorization', `Bearer ${RPC_AUTH}`)
12+
const provider = new ethers.JsonRpcProvider(fetchRequest)
13+
const smartContractClient = new ethers.Contract(
14+
MINER_TO_PEERID_CONTRACT_ADDRESS,
15+
MINER_TO_PEERID_CONTRACT_ABI,
16+
provider
17+
)
2418

2519
/**
26-
* @param {string} minerId A miner actor id, e.g. `f0142637`
27-
* @param {object} options
28-
* @param {number} [options.maxAttempts]
29-
* @returns {Promise<string>} Miner's PeerId, e.g. `12D3KooWMsPmAA65yHAHgbxgh7CPkEctJHZMeM3rAvoW8CZKxtpG`
20+
* @param {string} minerId - The ID of the miner.
21+
* @param {object} options - Options for the function.
22+
* @param {number} options.maxAttempts - The maximum number of attempts to fetch the peer ID.
23+
* @returns {Promise<string>} The peer ID of the miner.
3024
*/
31-
export async function getMinerPeerId (minerId, { maxAttempts = 5 } = {}) {
32-
const chainHead = await getChainHead({ maxAttempts })
25+
export async function getIndexProviderPeerId (minerId, { maxAttempts = 5 } = {}) {
3326
try {
34-
const res = await retry(() => rpc('Filecoin.StateMinerInfo', minerId, chainHead), {
35-
// The maximum amount of attempts until failure.
27+
const { peerId, source } = await getPeerId(minerId, smartContractClient, {
28+
rpcUrl: RPC_URL,
29+
rpcAuth: RPC_AUTH,
3630
maxAttempts,
37-
// The initial and minimum amount of milliseconds between attempts.
38-
minTimeout: 5_000,
39-
// How much to backoff after each retry.
40-
multiplier: 1.5
31+
signal: AbortSignal.timeout(60_000)
4132
})
42-
return res.PeerId
33+
console.log(`Peer ID fetched from ${source}.`)
34+
return peerId
4335
} catch (err) {
44-
if (err.name === 'RetryError' && err.cause) {
45-
// eslint-disable-next-line no-ex-assign
46-
err = err.cause
47-
}
48-
err.message = `Cannot obtain miner info for ${minerId}: ${err.message}`
49-
throw err
50-
}
51-
}
52-
53-
/**
54-
* @param {string} method
55-
* @param {unknown[]} params
56-
*/
57-
async function rpc (method, ...params) {
58-
const req = new Request(RPC_URL, {
59-
method: 'POST',
60-
headers: {
61-
'content-type': 'application/json',
62-
accepts: 'application/json',
63-
authorization: `Bearer ${RPC_AUTH}`
64-
},
65-
body: JSON.stringify({
66-
jsonrpc: '2.0',
67-
id: 1,
68-
method,
69-
params
70-
})
71-
})
72-
const res = await fetch(req, {
73-
signal: AbortSignal.timeout(60_000)
74-
})
75-
76-
if (!res.ok) {
77-
throw new Error(`JSON RPC failed with ${res.code}: ${(await res.text()).trimEnd()}`)
78-
}
79-
80-
const body = await res.json()
81-
if (body.error) {
82-
const err = new Error(body.error.message)
83-
err.name = 'FilecoinRpcError'
84-
err.code = body.code
36+
console.error(err)
8537
throw err
8638
}
87-
88-
return body.result
8939
}

lib/spot-checker.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* global Zinnia */
22

33
import { queryTheIndex } from './ipni-client.js'
4-
import { getMinerPeerId as defaultGetMinerPeerId } from './miner-info.js'
4+
import { getIndexProviderPeerId as defaultGetIndexProviderPeerId } from './miner-info.js'
55
import { Tasker } from './tasker.js'
66

77
import {
@@ -19,15 +19,15 @@ import { validateHttpMultiaddr } from './multiaddr.js'
1919

2020
export default class SpotChecker {
2121
#fetch
22-
#getMinerPeerId
22+
#getIndexProviderPeerId
2323
#tasker
2424

2525
constructor ({
2626
fetch = globalThis.fetch,
27-
getMinerPeerId = defaultGetMinerPeerId
27+
getIndexProviderPeerId = defaultGetIndexProviderPeerId
2828
} = {}) {
2929
this.#fetch = fetch
30-
this.#getMinerPeerId = getMinerPeerId
30+
this.#getIndexProviderPeerId = getIndexProviderPeerId
3131
this.#tasker = new Tasker({ fetch: this.#fetch })
3232
}
3333

@@ -41,7 +41,7 @@ export default class SpotChecker {
4141
async executeSpotCheck ({ task, stats, maxByteLength }) {
4242
console.log(`Calling Filecoin JSON-RPC to get PeerId of miner ${task.minerId}`)
4343
try {
44-
const peerId = await this.#getMinerPeerId(task.minerId)
44+
const peerId = await this.#getIndexProviderPeerId(task.minerId)
4545
console.log(`Found peer id: ${peerId}`)
4646
stats.providerId = peerId
4747
} catch (err) {

main.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import SpotChecker from './lib/spot-checker.js'
2-
import { getMinerPeerId as defaultGetMinerPeerId } from './lib/miner-info.js'
2+
import { getIndexProviderPeerId as defaultGetIndexProviderPeerId } from './lib/miner-info.js'
33
import { roundId, maxTasks, minerId, maxByteLength, retrievalTasks } from './config.js'
44

55
/**
@@ -12,10 +12,10 @@ import { roundId, maxTasks, minerId, maxByteLength, retrievalTasks } from './con
1212
* Configuration options can be found in config.js
1313
*
1414
*/
15-
const getMinerPeerId = (minerId) =>
15+
const getIndexProviderPeerId = (minerId) =>
1616
minerId === 'f0frisbii'
1717
? '12D3KooWC8gXxg9LoJ9h3hy3jzBkEAxamyHEQJKtRmAuBuvoMzpr'
18-
: defaultGetMinerPeerId(minerId)
18+
: defaultGetIndexProviderPeerId(minerId)
1919

20-
const checker = new SpotChecker({ getMinerPeerId })
20+
const checker = new SpotChecker({ getIndexProviderPeerId })
2121
await checker.run({ roundId, maxTasks, retrievalTasks, minerId, maxByteLength })

test/integration.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import SpotChecker, { newStats } from '../lib/spot-checker.js'
22
import { test } from 'zinnia:test'
33
import { assertEquals } from 'zinnia:assert'
4-
import { getMinerPeerId as defaultGetMinerPeerId } from '../lib/miner-info.js'
4+
import { getIndexProviderPeerId as defaultGetIndexProviderPeerId } from '../lib/miner-info.js'
55

66
test('can execute spot check for our CID', async () => {
77
// The task to check, replace with your own values
@@ -10,13 +10,13 @@ test('can execute spot check for our CID', async () => {
1010
minerId: 'f0frisbii'
1111
}
1212

13-
const getMinerPeerId = (minerId) =>
13+
const getIndexProviderPeerId = (minerId) =>
1414
minerId === 'f0frisbii'
1515
? '12D3KooWC8gXxg9LoJ9h3hy3jzBkEAxamyHEQJKtRmAuBuvoMzpr'
16-
: defaultGetMinerPeerId(minerId)
16+
: defaultGetIndexProviderPeerId(minerId)
1717

1818
// Run the check
19-
const spark = new SpotChecker({ getMinerPeerId })
19+
const spark = new SpotChecker({ getIndexProviderPeerId })
2020
const stats = { ...task, ...newStats() }
2121
await spark.executeSpotCheck({ task, stats })
2222

test/miner-info.test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import { test } from 'zinnia:test'
22
import { assertMatch, AssertionError } from 'zinnia:assert'
3-
import { getMinerPeerId } from '../lib/miner-info.js'
3+
import { getIndexProviderPeerId } from '../lib/miner-info.js'
44

55
const KNOWN_MINER_ID = 'f0142637'
66

77
test('get peer id of a known miner', async () => {
8-
const result = await getMinerPeerId(KNOWN_MINER_ID)
8+
const result = await getIndexProviderPeerId(KNOWN_MINER_ID)
99
assertMatch(result, /^12D3KooW/)
1010
})
1111

1212
test('get peer id of a miner that does not exist', async () => {
1313
try {
14-
const result = await getMinerPeerId('f010', { maxAttempts: 1 })
14+
const result = await getIndexProviderPeerId('f010', { maxAttempts: 1 })
1515
throw new AssertionError(
16-
`Expected "getMinerPeerId()" to fail, but it resolved with "${result}" instead.`
16+
`Expected "getIndexProviderPeerId()" to fail, but it resolved with "${result}" instead.`
1717
)
1818
} catch (err) {
19-
assertMatch(err.toString(), /\bf010\b.*\bactor code is not miner/)
19+
assertMatch(err.toString(), /Error fetching index provider PeerID for miner f010/)
2020
}
2121
})

0 commit comments

Comments
 (0)