explorer-api: populate per-block Addresses from verbose getblock tx outputs

This commit is contained in:
Sami
2026-06-15 00:48:17 -07:00
parent 293e3abcac
commit 7912ec363b
+38 -2
View File
@@ -64,6 +64,42 @@ async function rpc(method, params = []) {
} }
} }
// --- Block address enrichment -------------------------------------------------
// Attach the distinct addresses appearing in a block's transaction outputs.
// Triangles has a transparent ledger (addressindex/txindex enabled), so these
// are public. Privacy in Triangles is network-level (Tor) + encrypted SMSG
// messaging, not shielded transactions, so surfacing per-block addresses is fine.
async function attachAddresses(block) {
if (!block || !Array.isArray(block.tx)) return block;
const addrSet = new Set();
for (const entry of block.tx.slice(0, 50)) {
// getblock(verbose) gives full tx objects here; fall back to a lookup if
// we only got a txid string.
let tx = entry;
if (typeof entry === 'string') {
try { tx = await rpc('getrawtransaction', [entry, 1]); }
catch (e) { continue; }
}
for (const vout of ((tx && tx.vout) || [])) {
const addrs = vout.scriptPubKey && vout.scriptPubKey.addresses;
if (Array.isArray(addrs)) addrs.forEach((a) => addrSet.add(a));
}
}
block.addresses = Array.from(addrSet);
return block;
}
// getblock + address enrichment, cached by hash (blocks are immutable).
async function getEnrichedBlock(hash) {
const key = 'eblock:' + hash;
const cached = getCached(key);
if (cached) return cached;
const block = await rpc('getblock', [hash, true]);
await attachAddresses(block);
setCache(key, block);
return block;
}
// REST endpoint: /rest/chaininfo (with cache for expensive gettxoutsetinfo) // REST endpoint: /rest/chaininfo (with cache for expensive gettxoutsetinfo)
app.get('/rest/chaininfo', async (req, res) => { app.get('/rest/chaininfo', async (req, res) => {
try { try {
@@ -101,7 +137,7 @@ app.get('/rest/chaininfo', async (req, res) => {
// REST endpoint: /rest/block/:hash // REST endpoint: /rest/block/:hash
app.get('/rest/block/:hash', async (req, res) => { app.get('/rest/block/:hash', async (req, res) => {
try { try {
const block = await rpc('getblock', [req.params.hash, true]); // true = verbose with tx data const block = await getEnrichedBlock(req.params.hash);
res.json(block); res.json(block);
} catch (error) { } catch (error) {
res.status(404).json({ error: 'Block not found' }); res.status(404).json({ error: 'Block not found' });
@@ -112,7 +148,7 @@ app.get('/rest/block/:hash', async (req, res) => {
app.get('/rest/blockbyheight/:height', async (req, res) => { app.get('/rest/blockbyheight/:height', async (req, res) => {
try { try {
const hash = await rpc('getblockhash', [parseInt(req.params.height)]); const hash = await rpc('getblockhash', [parseInt(req.params.height)]);
const block = await rpc('getblock', [hash, true]); // true = verbose const block = await getEnrichedBlock(hash);
res.json(block); res.json(block);
} catch (error) { } catch (error) {
res.status(404).json({ error: 'Block not found' }); res.status(404).json({ error: 'Block not found' });