Public
Edited
Oct 13, 2023
Insert cell
Insert cell
Insert cell
Insert cell
await client.version()
Insert cell
chainHead = await client.chainHead()
Insert cell
Insert cell
headTipSet = chainHead.Cids
Insert cell
viewof selectedHeight = html`<input type=range min=${currentHeight - 11000} max=${currentHeight - 1} value=${currentHeight - 50}>`
Insert cell
Insert cell
md`${currentHeight - selectedHeight} epochs (${dateFns.formatDistance(epochToDate(currentHeight), epochToDate(selectedHeight), { includeSeconds: true })})`
Insert cell
viewof start = Inputs.button("Start")
Insert cell
maxElapsed = 7.5 * 60 * 1000 // 7.5 minutes
Insert cell
Insert cell
async function * heightRangeStream() {
if (start > 0) {
for (let height = selectedHeight; height < currentHeight; height++) {
yield height
}
}
}
Insert cell
async function * tipSetStream() {
for await (const height of heightRangeStream()) {
const tipSet = await client.chainGetTipSetByHeight(height, headTipSet)
if (tipSet.Height == height) {
yield {
height,
tipSet
}
}
}
}
Insert cell
tipSets = {
const result = []
/* for await (const tipSet of tipSetStream()) {
result.push(tipSet)
} */
return result
}
Insert cell
// tipSet = [...tipSetKey].map(obj => obj['/']).sort().join(',')

Insert cell
async function* messagesStream() {
let hits = 0
let messagesProcessed = 0
let aborted = false
const startTime = new Date()
for await (const tipSetRecord of tipSetStream()) {
const seenMessages = new Set()
const selectedTipSet = tipSetRecord.tipSet
let cso
let csoStartTime
if (selectedTipSet.Cids) {
const height = selectedTipSet.Height
console.log(`${height}, ${currentHeight - height} remaining`)
for (let i = 0; i < selectedTipSet.Cids.length; i++) {
const blockCid = selectedTipSet.Cids[i]
const blockMiner = selectedTipSet.Blocks[i].Miner
const now = new Date()
if (now - startTime > maxElapsed) {
yield {
done: true,
timeout: true
}
return
}
yield {
height,
blockMiner,
i,
length: selectedTipSet.Cids.length,
startHeight: selectedHeight,
endHeight: currentHeight,
messagesProcessed,
hits
}
try {
const messages = await client.chainGetBlockMessages(blockCid)
for (const message of messages.BlsMessages) {
yield *yieldMessage(message, 'bls')
if (aborted) return
}
} catch (e) {
console.error('messages error', height, e)
}
/* Non-miners shouldn't publish deals
for (const { Message: message } of messages.SecpkMessages) {
yield *yieldMessage(message, 'secpk')
}
*/
async function *yieldMessage (message, signatureType) {
messagesProcessed++
if (message.To === 'f05' && message.Method === 4) {
console.log('JimX message', message)
const blockCidStr = blockCid['/']
const messageCidStr = message.CID['/']
if (seenMessages.has(messageCidStr)) return
hits++
seenMessages.add(messageCidStr)

if (!cso) {
// Compute state to get results
console.log('StateCompute', height)
csoStartTime = new Date()
cso = client.stateCompute(height, null, selectedTipSet.Cids)
}
const timeoutTimer = new Promise(
(resolve, reject) =>
setTimeout(() => resolve({ timeout: 1 }), apiTimeout)
)
const results = await Promise.race([timeoutTimer, cso])
const elapsed = ((new Date()) - csoStartTime) / 1000
if (results?.timeout) {
console.log('Jim timeout', elapsed )
yield {
done: true,
abort: true,
timeout: true
}
aborted = true
return
}
const trace = results.Trace.filter(({ MsgCid }) => MsgCid['/'] === messageCidStr)
console.log('StateCompute done', height, results.Trace.length, elapsed)

if (trace.length > 0 && trace[0].MsgRct.Return) {
yield {
height,
messageCid: messageCidStr,
// signatureType,
blockCid: blockCidStr,
version: message.Version,
to: message.To,
from: message.From,
nonce: message.Nonce,
value: message.Value,
gasLimit: message.GasLimit,
gasFeeCap: message.GasFeeCap,
gasPremium: message.GasPremium,
method: message.Method,
params: message.Params,
decodedDeals: decodeDeals(message.Params),
results: cbor.decode(trace[0].MsgRct.Return, 'base64')[0]
}
} else {
console.error('Missing or broken trace', height, messageCidStr)
}
}
}
}
}
}
yield { done: true }
}
Insert cell
// messagesStream()
Insert cell
messages = {
const result = []
/* for await (const message of messagesStream()) {
if (message.messageCid) {
result.push(message)
yield result
}
} */
}
Insert cell
async function* dealStream() {
for await (const message of messagesStream()) {
if (message.startHeight) {
yield {
height: message.height,
startHeight: message.startHeight,
endHeight: message.endHeight,
messagesProcessed: message.messagesProcessed,
messageHits: message.hits
}
}
if (message.decodedDeals) {
const messageTime = epochToDate(message.height).toISOString()
for (let i = 0; i < message.decodedDeals.length; i++) {
yield {
dealId: message.results[i],
messageHeight: message.height,
messageTime,
messageCid: message.messageCid,
...message.decodedDeals[i],
startTime: epochToDate(message.decodedDeals[i].startEpoch).toISOString(),
endTime: epochToDate(message.decodedDeals[i].endEpoch).toISOString()
}
}
}
}
}
Insert cell
// dealStream()
Insert cell
deals.state === 'done' ? `Done. ${deals.endHeight - deals.lastHeight} epochs remaining.` : `${dateFns.formatDistance(deals.elapsed * 1000, 0)} - ${deals.height}, ${deals.endHeight - deals.height} remaining`
Insert cell
deals = {
if (start === 0) {
yield {
state: 'paused'
}
return
}
yield {
state: 'starting'
}
const deals = []
const startTime = new Date()
let height
let startHeight
let endHeight
let messagesProcessed
let messageHits
for await (const deal of dealStream()) {
if (deal.height) {
height = deal.height
startHeight = deal.startHeight
endHeight = deal.endHeight
messagesProcessed = deal.messagesProcessed
messageHits = deal.messageHits
}
if (deal.dealId) {
deals.push(deal)
}
yield {
state: 'streaming',
elapsed: ((new Date()) - startTime) / 1000,
dealsLength: deals.length,
height,
startHeight,
endHeight,
messagesProcessed,
messageHits
}
}
const endTime = new Date()
yield {
state: 'done',
elapsed: (endTime - startTime) / 1000,
deals,
startTime: startTime.toISOString(),
endTime: endTime.toISOString(),
lastHeight: height,
startHeight,
endHeight,
messagesProcessed,
messageHits
}
console.log('Done.', dateFns.formatDistance(endTime, startTime))
}
Insert cell
Insert cell
LotusRPC = (await import('@filecoin-shipyard/lotus-client-rpc')).LotusRPC
Insert cell
BrowserProvider = (await import('@filecoin-shipyard/lotus-client-provider-browser')).BrowserProvider
Insert cell
schema = (await import('@filecoin-shipyard/lotus-client-schema')).mainnet.fullNode
Insert cell
Insert cell
Object.keys(schema.methods)
Insert cell
Insert cell
endpointUrl = {
return "https://lotus.miner.report/mainnet_api/0/node/rpc/v0"
// return "https://lotus.jimpick.com/mainnet_api/0/node/rpc/v0"
// return "https://api.node.glif.io/rpc/v0"
// return "wss://api.chain.love/rpc/v0"
}
Insert cell
client = {
const provider = new BrowserProvider(endpointUrl)
return new LotusRPC(provider, { schema })
}
Insert cell
Insert cell
Insert cell
cbor = import('https://cdn.skypack.dev/borc')
Insert cell
Insert cell
dateFns = require('https://bundle.run/date-fns@2.22.1')
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more