|
1 |
| -import { retry } from '../vendor/deno-deps.js' |
2 | 1 | import { RPC_URL, RPC_AUTH } from './constants.js'
|
3 |
| -import { getIndexProviderPeerIdFromSmartContract } from './smart-contract-client.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' |
| 8 | + |
| 9 | +// Initialize contract |
| 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 | +) |
4 | 18 |
|
5 | 19 | /**
|
6 |
| - * @param {object} options |
7 |
| - * @param {number} [options.maxAttempts] |
8 |
| - * @param {function} [options.rpcFn] |
9 |
| - * @returns {Promise<string>} The chain head Cid |
| 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. |
10 | 24 | */
|
11 |
| -async function getChainHead({ maxAttempts = 5, rpcFn } = {}) { |
| 25 | +export async function getIndexProviderPeerId(minerId, { maxAttempts = 5 } = {}) { |
12 | 26 | try {
|
13 |
| - const res = await retry(() => (rpcFn ?? rpc)('Filecoin.ChainHead'), { |
14 |
| - // The maximum amount of attempts until failure. |
| 27 | + const { peerId, source } = await getPeerId(minerId, smartContractClient, { |
| 28 | + rpcUrl: RPC_URL, |
| 29 | + rpcAuth: RPC_AUTH, |
15 | 30 | maxAttempts,
|
16 |
| - // The initial and minimum amount of milliseconds between attempts. |
17 |
| - minTimeout: 5_000, |
18 |
| - // How much to backoff after each retry. |
19 |
| - multiplier: 1.5, |
| 31 | + signal: AbortSignal.timeout(60_000), |
20 | 32 | })
|
21 |
| - return res.Cids |
| 33 | + console.log(`Peer ID fetched from ${source}.`) |
| 34 | + return peerId |
22 | 35 | } catch (err) {
|
23 |
| - if (err.name === 'RetryError' && err.cause) { |
24 |
| - // eslint-disable-next-line no-ex-assign |
25 |
| - err = err.cause |
26 |
| - } |
27 |
| - err.message = `Cannot obtain chain head: ${err.message}` |
| 36 | + console.error(err) |
28 | 37 | throw err
|
29 | 38 | }
|
30 | 39 | }
|
31 |
| - |
32 |
| -/** |
33 |
| - * @param {string} minerId A miner actor id, e.g. `f0142637` |
34 |
| - * @param {object} options |
35 |
| - * @param {number} [options.maxAttempts] |
36 |
| - * @returns {Promise<string>} Miner's PeerId, e.g. `12D3KooWMsPmAA65yHAHgbxgh7CPkEctJHZMeM3rAvoW8CZKxtpG` |
37 |
| - */ |
38 |
| -export async function getIndexProviderPeerId( |
39 |
| - minerId, |
40 |
| - { maxAttempts = 5, smartContract, rpcFn } = {}, |
41 |
| -) { |
42 |
| - try { |
43 |
| - // Make a concurrent request to both sources: FilecoinMinerInfo and smart contract |
44 |
| - const [minerInfoResult, contractResult] = await Promise.all([ |
45 |
| - getIndexProviderPeerIdFromFilecoinMinerInfo(minerId, { maxAttempts, rpcFn }), |
46 |
| - getIndexProviderPeerIdFromSmartContract(minerId, { smartContract }), |
47 |
| - ]) |
48 |
| - // Check contract result first |
49 |
| - if (contractResult) { |
50 |
| - console.log('Using PeerID from the smart contract.') |
51 |
| - return contractResult |
52 |
| - } |
53 |
| - |
54 |
| - // Fall back to FilecoinMinerInfo result |
55 |
| - if (minerInfoResult) { |
56 |
| - console.log('Using PeerID from FilecoinMinerInfo.') |
57 |
| - return minerInfoResult |
58 |
| - } |
59 |
| - |
60 |
| - // Handle the case where both failed |
61 |
| - throw new Error( |
62 |
| - `Failed to obtain Miner's Index Provider PeerID.\nSmartContract query result: ${contractResult}\nStateMinerInfo query result: ${minerInfoResult}`, |
63 |
| - ) |
64 |
| - } catch (error) { |
65 |
| - console.error('Error fetching PeerID:', error) |
66 |
| - throw Error(`Error fetching PeerID for miner ${minerId}.`, { |
67 |
| - cause: error, |
68 |
| - }) |
69 |
| - } |
70 |
| -} |
71 |
| - |
72 |
| -/** |
73 |
| - * @param {string} minerId A miner actor id, e.g. `f0142637` |
74 |
| - * @param {object} options |
75 |
| - * @param {number} [options.maxAttempts] |
76 |
| - * @param {function} [options.rpcFn] |
77 |
| - * @returns {Promise<string>} Miner's PeerId, e.g. `12D3KooWMsPmAA65yHAHgbxgh7CPkEctJHZMeM3rAvoW8CZKxtpG` |
78 |
| - */ |
79 |
| -export async function getIndexProviderPeerIdFromFilecoinMinerInfo( |
80 |
| - minerId, |
81 |
| - { maxAttempts = 5, rpcFn } = {}, |
82 |
| -) { |
83 |
| - const chainHead = await getChainHead({ maxAttempts, rpcFn }) |
84 |
| - try { |
85 |
| - const res = await retry(() => (rpcFn ?? rpc)('Filecoin.StateMinerInfo', minerId, chainHead), { |
86 |
| - // The maximum amount of attempts until failure. |
87 |
| - maxAttempts, |
88 |
| - // The initial and minimum amount of milliseconds between attempts. |
89 |
| - minTimeout: 5_000, |
90 |
| - // How much to backoff after each retry. |
91 |
| - multiplier: 1.5, |
92 |
| - }) |
93 |
| - return res.PeerId |
94 |
| - } catch (err) { |
95 |
| - if (err.name === 'RetryError' && err.cause) { |
96 |
| - // eslint-disable-next-line no-ex-assign |
97 |
| - err = err.cause |
98 |
| - } |
99 |
| - err.message = `Cannot obtain miner info for ${minerId}: ${err.message}` |
100 |
| - throw err |
101 |
| - } |
102 |
| -} |
103 |
| - |
104 |
| -/** |
105 |
| - * @param {string} method |
106 |
| - * @param {unknown[]} params |
107 |
| - */ |
108 |
| -async function rpc(method, ...params) { |
109 |
| - const req = new Request(RPC_URL, { |
110 |
| - method: 'POST', |
111 |
| - headers: { |
112 |
| - 'content-type': 'application/json', |
113 |
| - accepts: 'application/json', |
114 |
| - authorization: `Bearer ${RPC_AUTH}`, |
115 |
| - }, |
116 |
| - body: JSON.stringify({ |
117 |
| - jsonrpc: '2.0', |
118 |
| - id: 1, |
119 |
| - method, |
120 |
| - params, |
121 |
| - }), |
122 |
| - }) |
123 |
| - const res = await fetch(req, { |
124 |
| - signal: AbortSignal.timeout(60_000), |
125 |
| - }) |
126 |
| - |
127 |
| - if (!res.ok) { |
128 |
| - throw new Error(`JSON RPC failed with ${res.code}: ${(await res.text()).trimEnd()}`) |
129 |
| - } |
130 |
| - |
131 |
| - const body = await res.json() |
132 |
| - if (body.error) { |
133 |
| - const err = new Error(body.error.message) |
134 |
| - err.name = 'FilecoinRpcError' |
135 |
| - err.code = body.code |
136 |
| - throw err |
137 |
| - } |
138 |
| - |
139 |
| - return body.result |
140 |
| -} |
0 commit comments