mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo-db.git
synced 2026-09-21 16:52:02 -07:00
Adding endpoints for profile page
This commit is contained in:
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
Utility: backfill profile `seen` timestamps from on-chain block header times.
|
||||
|
||||
Reads each profile's txid, looks up blockHeight in ptxs, fetches block header
|
||||
time via BCH RPC, and writes seen = block.time * 1000 (Unix ms).
|
||||
|
||||
Run from the psf-memo-db repo root (memo-db must be stopped to avoid lock conflicts):
|
||||
node util/profiles/backfill_seen.js
|
||||
|
||||
Environment (same as psf-memo-indexer):
|
||||
RPC_IP, RPC_PORT, RPC_USER, RPC_PASS
|
||||
*/
|
||||
|
||||
import 'dotenv/config'
|
||||
import level from 'level'
|
||||
import * as url from 'url'
|
||||
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
const rpcIp = process.env.RPC_IP || '172.17.0.1'
|
||||
const rpcPort = process.env.RPC_PORT || '8332'
|
||||
const rpcUser = process.env.RPC_USER || 'bitcoin'
|
||||
const rpcPass = process.env.RPC_PASS || 'password'
|
||||
|
||||
const profilesDb = level(`${__dirname}/../../leveldb/current/profiles`, {
|
||||
valueEncoding: 'json'
|
||||
})
|
||||
|
||||
const ptxsDb = level(`${__dirname}/../../leveldb/current/ptxs`, {
|
||||
valueEncoding: 'json'
|
||||
})
|
||||
|
||||
const blockTimeCache = new Map()
|
||||
|
||||
async function rpcCall (method, params = []) {
|
||||
const response = await fetch(`http://${rpcIp}:${rpcPort}/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Basic ${Buffer.from(`${rpcUser}:${rpcPass}`).toString('base64')}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
jsonrpc: '1.0',
|
||||
id: method,
|
||||
method,
|
||||
params
|
||||
})
|
||||
})
|
||||
|
||||
const body = await response.json()
|
||||
if (body.error) {
|
||||
throw new Error(body.error.message || `RPC ${method} failed`)
|
||||
}
|
||||
return body.result
|
||||
}
|
||||
|
||||
async function getBlockTimeMs (blockHeight) {
|
||||
if (blockTimeCache.has(blockHeight)) {
|
||||
return blockTimeCache.get(blockHeight)
|
||||
}
|
||||
|
||||
const hash = await rpcCall('getblockhash', [blockHeight])
|
||||
const header = await rpcCall('getblockheader', [hash, true])
|
||||
const seen = header.time * 1000
|
||||
blockTimeCache.set(blockHeight, seen)
|
||||
return seen
|
||||
}
|
||||
|
||||
async function backfillProfiles () {
|
||||
let updated = 0
|
||||
let skipped = 0
|
||||
let errors = 0
|
||||
|
||||
try {
|
||||
for await (const [addr, profile] of profilesDb.iterator()) {
|
||||
try {
|
||||
if (!profile.txid) {
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
const ptx = await ptxsDb.get(profile.txid)
|
||||
if (!ptx || ptx.blockHeight === undefined) {
|
||||
console.warn(`No ptx blockHeight for ${addr} txid ${profile.txid}`)
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
const seen = await getBlockTimeMs(ptx.blockHeight)
|
||||
if (profile.seen === seen) {
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
await profilesDb.put(addr, { ...profile, seen })
|
||||
updated++
|
||||
console.log(`${addr}: seen ${profile.seen} -> ${seen} (block ${ptx.blockHeight})`)
|
||||
} catch (err) {
|
||||
errors++
|
||||
console.error(`Error updating ${addr}:`, err.message)
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\nBackfill complete. Updated: ${updated}, skipped: ${skipped}, errors: ${errors}`)
|
||||
} finally {
|
||||
await profilesDb.close()
|
||||
await ptxsDb.close()
|
||||
}
|
||||
}
|
||||
|
||||
backfillProfiles().catch((err) => {
|
||||
console.error('Backfill failed:', err.message)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user