Skip to content
This repository was archived by the owner on Jan 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 14 additions & 10 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@
// deno bundle deps.ts vendor/deno-deps.js
//

export { encodeHex } from 'https://deno.land/std@0.203.0/encoding/hex.ts'
export { decodeBase64 } from 'https://deno.land/std@0.203.0/encoding/base64.ts'
export { decode as decodeVarint } from 'https://deno.land/x/varint@v2.0.0/varint.ts'
export { retry } from 'https://deno.land/std@0.203.0/async/retry.ts';

export { encodeHex } from "https://deno.land/std@0.203.0/encoding/hex.ts";
export { decodeBase64 } from "https://deno.land/std@0.203.0/encoding/base64.ts";
export { decode as decodeVarint } from "https://deno.land/x/varint@v2.0.0/varint.ts";

// Deno Bundle does not support npm dependencies, we have to load them via CDN
export { CarBlockIterator } from 'https://cdn.skypack.dev/@ipld/car@5.3.2/?dts'
export { CarBlockIterator } from "https://cdn.skypack.dev/@ipld/car@5.3.2/?dts";
export {
getIndexProviderPeerId,
MINER_TO_PEERID_CONTRACT_ADDRESS,
MINER_TO_PEERID_CONTRACT_ABI,
} from "https://cdn.jsdelivr.net/npm/index-provider-peer-id@1.0.0/index.js/+esm";
export { ethers } from "https://cdn.jsdelivr.net/npm/ethers@6.13.5/dist/ethers.min.js";
export {
UnsupportedHashError,
HashMismatchError,
validateBlock
} from 'https://cdn.skypack.dev/@web3-storage/car-block-validator@1.2.0/?dts'
validateBlock,
} from "https://cdn.skypack.dev/@web3-storage/car-block-validator@1.2.0/?dts";
// cdn.skypack.dev cannot resolve import from @noble/hashes
// jsdelivr.net seems to work better, it's also recommended by drand-client
export {
fetchBeaconByTime,
HttpChainClient,
HttpCachingChain
} from 'https://cdn.jsdelivr.net/npm/drand-client@1.2.6/index.js/+esm'
HttpCachingChain,
} from "https://cdn.jsdelivr.net/npm/drand-client@1.2.6/index.js/+esm";
106 changes: 25 additions & 81 deletions lib/miner-info.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,33 @@
import { retry } from '../vendor/deno-deps.js'
import { RPC_URL, RPC_AUTH } from './constants.js'
import {
getIndexProviderPeerId,
MINER_TO_PEERID_CONTRACT_ADDRESS,
MINER_TO_PEERID_CONTRACT_ABI
, ethers
} from '../vendor/deno-deps.js'

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

/**
* @param {string} minerId A miner actor id, e.g. `f0142637`
* @param {object} options
* @param {number} [options.maxAttempts]
* @returns {Promise<string>} Miner's PeerId, e.g. `12D3KooWMsPmAA65yHAHgbxgh7CPkEctJHZMeM3rAvoW8CZKxtpG`
* @param {string} minerId - The ID of the miner.
* @param {object} options - Options for the function.
* @param {number} options.maxAttempts - The maximum number of attempts to fetch the peer ID.
* @returns {Promise<string>} The peer ID of the miner.
*/
export async function getMinerPeerId (minerId, { maxAttempts = 5 } = {}) {
const chainHead = await getChainHead({ maxAttempts })
try {
const res = await retry(() => rpc('Filecoin.StateMinerInfo', minerId, chainHead), {
// The maximum amount of attempts until failure.
maxAttempts,
// The initial and minimum amount of milliseconds between attempts.
minTimeout: 5_000,
// How much to backoff after each retry.
multiplier: 1.5
})
return res.PeerId
} catch (err) {
if (err.name === 'RetryError' && err.cause) {
// eslint-disable-next-line no-ex-assign
err = err.cause
}
err.message = `Cannot obtain miner info for ${minerId}: ${err.message}`
throw err
}
}

/**
* @param {string} method
* @param {unknown[]} params
*/
async function rpc (method, ...params) {
const req = new Request(RPC_URL, {
method: 'POST',
headers: {
'content-type': 'application/json',
accepts: 'application/json',
authorization: `Bearer ${RPC_AUTH}`
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method,
params
return (
await getIndexProviderPeerId(minerId, smartContractClient, {
rpcUrl: RPC_URL,
rpcAuth: RPC_AUTH,
maxAttempts
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is doing too much. Let's split it into two lines to make the code easier to read.

const { peerId } = await getIndexProviderPeerId(minerId, smartContractClient, {
  rpcUrl: RPC_URL,
  rpcAuth: RPC_AUTH,
  maxAttempts
})

return peerId

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in f66700e

})
const res = await fetch(req, {
signal: AbortSignal.timeout(60_000)
})

if (!res.ok) {
throw new Error(`JSON RPC failed with ${res.code}: ${(await res.text()).trimEnd()}`)
}

const body = await res.json()
if (body.error) {
const err = new Error(body.error.message)
err.name = 'FilecoinRpcError'
err.code = body.code
throw err
}

return body.result
).peerId
}
2 changes: 1 addition & 1 deletion test/miner-info.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ test('get peer id of a miner that does not exist', async () => {
`Expected "getMinerPeerId()" to fail, but it resolved with "${result}" instead.`
)
} catch (err) {
assertMatch(err.toString(), /\bf010\b.*\bactor code is not miner/)
assertMatch(err.toString(), /Error fetching index provider PeerID for miner f010/)
}
})
Loading