feat: pestaña Cadena unificada, aviso de polvo y enlaces a la instancia propia

Mempool y Bloques eran el mismo eje partido: los proyectados en una pestaña y
los confirmados en otra. Ahora es una línea temporal con el ahora en medio, y
responde la pregunta que ninguna de las dos respondía — a qué tarifa entra tu
transacción y en qué bloque.

Aviso de polvo recibido en el informe de wallet: el analizador sabía
reconocerlo al mirar una transacción, pero no avisaba cuando te pasaba a ti.
El consejo es no gastarlo, porque el daño solo ocurre al mezclarlo.

Enlaces a la instancia propia de Mempool en nueve puntos, construidos siempre
desde la URL configurada.

Y un fallo preexistente: el rastro de procedencia caía en mempool.space
público si no había nodo configurado. Sin nodo ya no hay enlace.
This commit is contained in:
2026-08-08 18:26:01 +02:00
parent 387af724ac
commit 643236e47b
3 changed files with 418 additions and 116 deletions
+27 -3
View File
@@ -290,12 +290,36 @@ async function getBitcoinInfo() {
// connections_in/out existen desde Core 0.21; fallback a getpeerinfo si no
let inbound = netinfo.connections_in;
let outbound = netinfo.connections_out;
let peerList = null;
if (inbound === undefined || outbound === undefined) {
const peers = await rpcCall("getpeerinfo").catch(() => null);
inbound = peers ? peers.filter(p => p.inbound).length : 0;
outbound = peers ? peers.filter(p => !p.inbound).length : 0;
peerList = await rpcCall("getpeerinfo").catch(() => null);
inbound = peerList ? peerList.filter(p => p.inbound).length : 0;
outbound = peerList ? peerList.filter(p => !p.inbound).length : 0;
}
// Por qué red entra cada peer, y qué direcciones anuncia el nodo.
// Hace falta para no dar por hecho que tener conexiones entrantes expone
// la IP: si entran por Tor o I2P no la ven, y si el nodo no anuncia
// ninguna dirección de clearnet, tampoco la publica a la red.
let inboundNets = null, clearnetLocal = null;
try {
if (!peerList) peerList = await rpcCall("getpeerinfo");
if (Array.isArray(peerList)) {
inboundNets = {};
for (const p of peerList.filter(p => p.inbound)) {
const n = p.network || "desconocida";
inboundNets[n] = (inboundNets[n] || 0) + 1;
}
}
const locales = netinfo.localaddresses || [];
clearnetLocal = locales
.filter(a => !/\.onion$|\.i2p$/i.test(a.address || ""))
.map(a => a.address);
} catch { /* si falla, se informa como no comprobado, no como ausencia */ }
return {
inboundNets, clearnetLocal,
localAddrCount: (netinfo.localaddresses || []).length,
version: `v${Math.floor(netinfo.version / 10000)}.${Math.floor((netinfo.version % 10000) / 100)}.${netinfo.version % 100}`,
blocks: info.blocks,
headers: info.headers,