Files
txoko-dashboard/CHANGELOG.md
T
Aitor d0f17e4bd8 fix: instalar-fuentes.sh fallaba en macOS por usar stat de GNU
Comprobaba el tamaño con 'stat -c%s'. macOS trae la versión BSD, que usa -f%z,
así que el comando fallaba, caía en el '|| echo 0' y el script daba por fallida
una descarga correcta: 'FALLÓ (HTTP 200, 0 bytes)'. El 200 decía que había ido
bien; lo roto era la comprobación.

Ahora usa wc -c, igual en los dos sistemas, y comprueba que el archivo exista.
La cabecera ya no dice 'ejecutar en el nodo': si el dashboard puede vivir en
una carpeta cualquiera, su instalador de fuentes también.
2026-08-08 19:27:23 +02:00

55 KiB
Raw Blame History

Changelog

Todos los cambios notables de Txoko Node Dashboard se documentan aquí.

El formato sigue Keep a Changelog y el versionado sigue Versionado Semántico: MAYOR.MENOR.PARCHE.

  • MAYOR — cambios grandes que cambian cómo se usa la herramienta
  • MENOR — características nuevas que no rompen lo anterior
  • PARCHE — arreglos de errores

[1.18.2] — 2026-08-08

Corregido

  • instalar-fuentes.sh daba por fallidas descargas que habían ido bien, en macOS. Comprobaba el tamaño con stat -c%s, que es sintaxis GNU. macOS trae la versión BSD de stat, que usa -f%z, así que el comando fallaba, caía en el || echo 0 y el script informaba «FALLÓ (HTTP 200, 0 bytes)». El HTTP 200 decía que la descarga había funcionado; lo roto era la comprobación.
    • El mensaje además engañaba: se lee como un problema de red o del servidor de fuentes, y era una incompatibilidad de shell entre dos sistemas.
    • Ahora usa wc -c, que se comporta igual en Linux y en macOS, y comprueba antes que el archivo exista.
    • La cabecera del script decía «Ejecutar EN EL NODO». Ya no: si el dashboard puede vivir en una carpeta cualquiera, su instalador de fuentes tiene que funcionar ahí también.

[1.18.1] — 2026-08-08

Corregido

  • El aviso del xpub decía una media verdad. El panel de wallet watch-only decía «Txoko deriva tus direcciones en local — el xpub no sale del navegador». Es cierto, y por eso mismo engaña: el xpub no sale, pero las direcciones derivadas sí, una consulta a la API del nodo por cada una. Quien opere ese nodo puede ver en sus registros el monedero completo que estás analizando: cuántas direcciones tienes, cuáles, su historial y tu saldo.
    • Con el nodo propio no hay problema, es tu información en tu máquina. Con el nodo de otra persona —aunque sea de confianza— le estás enseñando tus finanzas enteras.
    • El aviso lo dice ahora, y distingue los dos casos. En una herramienta que existe para no afirmar de más, ese era el peor sitio posible para tener una frase técnicamente cierta que se lee como una garantía que no es.

Añadido

  • PRUEBALA.md — guía para quien recibe la aplicación para probarla: el aviso del xpub por delante de todo, qué merece la pena intentar romper, qué no hacer con el peritaje, y qué tipo de fallo interesa que reporte.

[1.18.0] — 2026-08-08

Añadido

  • La comisión como huella. El sat/vB que eliges dice algo del software y de quien lo maneja, y el dato estaba en cada transacción sin que nadie lo mirase. Se detectan dos firmas: una comisión absoluta redonda (10.000 sats clavados — un estimador nunca da eso, calcula tarifa por tamaño y devuelve números feos) y una tarifa prácticamente entera (20,00 sat/vB, que sale de teclear un número redondo en la casilla).
    • Informativo y sin penalización, por el mismo motivo que se decidió con RBF: la señal es débil, y bajar la nota por ella empujaría a elegir comisiones peores solo para disimular. Mal negocio.
  • El cambio ya se identifica en transacciones de más de dos salidas, cuando el caso es inequívoco. Antes la detección se plantaba en seco por encima de dos salidas. Estaba bien argumentado, pero se tiraba información sólida: si de N salidas exactamente una comparte tipo de script con las entradas, no hay nada que adivinar — y con más salidas la coincidencia por azar es aún más improbable que con dos. También cuenta el caso de una salida que vuelve a una dirección ya gastada. Se marca POSIBLE y no PROBABLE: es una sola señal, y hay monederos que devuelven el cambio a un tipo distinto del que gastan.
  • Aviso de autoenvíos que ataron direcciones, en el informe de wallet. Es una comprobación que solo cabe ahí: para saber que todas las salidas son tuyas hace falta conocer tu wallet entero, cosa que el analizador de una transacción suelta no puede saber.
    • Detecta las transacciones donde entradas y salidas son todas tuyas, y avisa solo cuando hubo daño real: más de una dirección de entrada. Mover una dirección a otra no vincula nada nuevo y no merece alarma.
    • Es un gesto que suele hacerse creyendo que despista y hace lo contrario: no hubo ningún pago, pero al firmar varias direcciones a la vez quedaron enlazadas en público. Se paga una comisión por empeorar la propia privacidad.

Con esto quedan cerradas las cinco heurísticas que el repaso del 2026-08-08 señaló como ausentes.


[1.17.0] — 2026-08-08

Cambiado

  • La nota de privacidad ya solo mide lo que dependía de ti. Hasta ahora mezclaba dos cosas distintas en un número: los errores propios (reutilizar direcciones, consolidar, dejar el cambio a la vista) y la exposición que provoca un tercero (que te paguen desde un lote, recibir polvo, que la otra parte use un tipo de dirección distinto). La consecuencia era absurda: alguien impecable que cobró de un exchange sacaba peor nota que un descuidado que cobró de un particular, y no había nada que pudiera hacer para mejorarla. Recibir de un lote costaba 23 puntos y estaba marcado, con razón, como "no corregible".
    • La nota se calcula ahora solo con los checks sobre los que tienes decisión. Denominador 142.
    • Lo demás pasa a un bloque propio, «lo que hicieron otros», con su propio nivel de exposición (ninguna / moderada / alta). Se informa, se explica, y no baja una nota que no podrías subir.
    • Una nota que no puedes mejorar no es una evaluación, es un reproche. Y una herramienta que reprocha lo que no elegiste enseña a ignorarla.
  • Un fallo grave impide la banda ALTA aunque el número dé de sobra. Con la nota restringida a lo propio, una transacción con el cambio identificable —una fuga real y concreta— sacaba 93 sobre 100 y la etiqueta "privacidad aceptable". Ahora cualquier check propio que falle con peso ≥10 impide la banda alta. Un promedio bueno no borra un fallo concreto.
  • OP_RETURN deja de forzar banda BAJA por decreto. Sigue penalizando, pero el tope duro condenaba por igual a una inscripción y a un sello de tiempo de OpenTimestamps, que es privacidad neutra. Como además OP_RETURN suele venir del protocolo que usaste y no de tu descuido, vive ahora en la exposición heredada.
  • Los cortes de banda pasan a 85 y 55: con la nota midiendo solo lo propio, el listón puede ser más exigente porque ya no hay dentro nada que no puedas arreglar.
  • La exportación en Markdown y en JSON incluyen ambos bloques por separado.

[1.16.0] — 2026-08-08

Corregido

  • El denominador de la nota de privacidad no cuadraba con los pesos. La nota se calcula como 100 - (deducciones / maxPossible) * 100, donde maxPossible es la suma del objeto weights. Ese objeto tenía dos desajustes, en direcciones opuestas y ninguno intencionado:
    • Incluía rbf (5) y peeling (8), que son informativos y nunca restan. Trece puntos de denominador imposibles de alcanzar, que inflaban sistemáticamente todas las notas.
    • No incluía input_linkage, que resta hasta 30 desde una variable suelta. Las deducciones podían superar al denominador en 17 puntos y dar una nota negativa, tapada solo por el Math.max(0, …).
    • Ahora todo lo que puede restar está en weights y nada más lo está. Los cortes de banda pasan de 75/45 a 79/54, que son los valores que hacen que una transacción reciba exactamente la misma banda que antes con el denominador corregido. Queda anotado en el código que normalizar por la suma de los pesos obliga a recalibrar cada vez que se añade un check — porque cada check nuevo hace parecer menos graves a los anteriores.
    • El texto explicativo bajo la nota derivaba la banda por su cuenta con los cortes antiguos escritos a mano. Ahora usa la banda ya calculada.
  • "Cifra redonda" estaba mal definido. La condición era v % 1000000 === 0 || v % 100000 === 0 || v % 10000000 === 0, donde la primera y la tercera sobran: todo múltiplo de un millón lo es de cien mil. Equivalía a "múltiplo de 0,001 BTC", así que pagos tan redondos como 10.000 o 50.000 sats —de lo más común con las comisiones de hoy— no se veían. La heurística estaba infrautilizada, no equivocada.
    • Ahora se mide por ceros finales y la señal se gradúa: pagar 0,5 BTC clavados delata más que pagar 0,0123, y la penalización lo refleja.
    • El didáctico dice ahora el punto ciego: si pagas una cantidad redonda en euros, en BTC sale un número con todos sus decimales y esta heurística no ve nada.

Añadido

  • Nuevo aviso: se gasta polvo junto a otras monedas. El check de polvo advertía de que una salida diminuta "quedará vinculada con las demás si se gasta junto a ellas" — y la aplicación nunca miraba si eso estaba ocurriendo delante de ella, pese a tener el dato en la mano. Ahora lo mira: si entre las entradas hay una moneda de tamaño polvo gastada junto a otras de importe normal, el ataque ya no es una hipótesis, se acaba de consumar, y se dice con CERTEZA. No aplica en CoinJoin ni cuando solo se gasta polvo, que no revela vinculación nueva.
  • La consolidación pura ya no pasa desapercibida. Una transacción de N entradas a una sola salida —el acto que más privacidad destruye de una vez— no disparaba el check de inputs innecesarios: su condición exige que una entrada cubra el pago y sobre, y en una consolidación la salida vale casi lo mismo que la suma de entradas. Comprobado con 20 entradas a 1 salida. Ahora se nombra como lo que es, con certeza. No suma penalización propia a propósito: la vinculación ya la cobra input_linkage, y cobrarla dos veces sería repetir el error que este mismo repaso acaba de corregir.
  • tests/test6.js — el analizador completo contra transacciones construidas a mano: coherencia de la nota, los dos checks nuevos y la guardia de CoinJoin.
  • tests/test5.js gana la comprobación de los niveles de redondez.
  • tests/README.md explica ahora las dos familias de prueba y deja escrito que las heurísticas se comprueban contra transacciones fabricadas, no contra la cadena real: eso demuestra que la lógica hace lo que dice, pero no cuántas veces acierta ahí fuera.

[1.15.0] — 2026-08-08

Corregido

  • La detección del cambio contaba una misma señal dos veces. La "señal A" (solo una salida comparte tipo de script con las entradas) y la "señal E" (el tipo de output difiere del de las entradas) eran la misma condición escrita dos veces —el mismo filter, la misma comparación, el mismo === 1— y cada una incrementaba el contador. Como el umbral para declarar el cambio identificable es de dos señales, ese único hecho bastaba por sí solo.
    • Consecuencia práctica: pagar desde una dirección bech32 a una taproot —de lo más común que hay— salía marcado como "cambio identificable" con certeza PROBABLE, sin ninguna otra evidencia.
    • Y el informe mostraba las dos señales juntas, que se contradicen entre sí: "tipo de script idéntico a inputs" y "tipo de output distinto al de inputs". El mismo hecho descrito con palabras opuestas.
    • Ahora es una sola señal. Esa transacción pasa a una señal y a no identificable, que es lo correcto. Cuando queda una sola señal el check lo dice en vez de callarse: existe, no basta, y conviene que se sepa que otro analista menos escrupuloso la daría por buena ella sola.
  • Se podía señalar el pago como si fuera el cambio. Cuando ninguna señal fuerte apuntaba a un output concreto, el índice caía en indexOf(smaller): se asumía que el cambio es siempre la salida menor. Es falso en el caso más común de todos —pagar poco desde una moneda grande—, donde el cambio es la salida mayor.
    • Comprobado con un pago de 0,001 BTC desde 1 BTC: la app decía en el detalle "el output redondo es el pago" y acto seguido señalaba ese mismo output como cambio. La información para acertar estaba delante y se descartaba.
    • Esto no se quedaba en el analizador: el motor de peritaje usa ese índice para detectar cadenas de peeling y para redactar el informe. Un cambio mal identificado significa presentar como rastro del actor la dirección del destinatario del pago, una persona ajena.
    • Ahora cada señal apunta a un output o reconoce que no puede. El orden de resolución es: reutilización de dirección de entrada → tipo de script → la salida NO redonda → posición. Si ninguna apunta, el índice queda vacío y se dice que hay señales pero no cuál — preferible a señalar mal.

Añadido

  • tests/test5.js — seis casos de detección de cambio con el pago y el cambio conocidos de antemano, incluidos los dos fallos anteriores como regresión.

[1.14.0] — 2026-08-08

Añadido

  • Mempool y Bloques se fusionan en una sola pestaña, «Cadena». Eran el mismo eje partido por la mitad: los "bloques proyectados" vivían en Mempool y los confirmados en Bloques, cuando es una línea temporal con el ahora en el corte. Ahora se lee de arriba abajo: comisiones, lo que está por minar, un separador AHORA, y los bloques ya minados.
    • Nuevo: «si pagas X sat/vB, ¿cuándo entra?». Ni la vista de mempool ni la de bloques respondían la pregunta que de verdad se hace quien mira las comisiones — daban los datos por separado y dejaban el cálculo al ojo. Escribes una tarifa y te dice en qué bloque proyectado caería, marcándolo en la lista. Con dos avisos escritos en la propia interfaz: el cálculo se hace sobre la mempool de este momento, y diez minutos es la media entre bloques, no una promesa.
    • El detalle de un bloque se abría al final de la lista, a quince filas del bloque pulsado, así que parecía que el clic no hacía nada. Ahora la vista se desplaza hasta él.
  • Aviso de polvo recibido en el informe de wallet. El analizador ya sabía reconocer el patrón al mirar una transacción suelta, pero eso no sirve si no te avisa cuando te pasa a ti. Recorre las salidas de importe ínfimo hacia direcciones propias y distingue las que siguen sin gastar —donde el consejo todavía sirve— de las ya gastadas, donde la vinculación ya está hecha. El consejo es el contrario del instinto: no hagas nada, déjalas quietas y congélalas en el monedero si puedes. El daño solo ocurre al mezclarlas.
  • Enlaces «ver en Mempool» en nueve puntos: transacción analizada, detalle de bloque y sus transacciones, dirección del explorador, historial del informe de wallet, direcciones atribuidas y fondos localizados del peritaje, y en el rastro de procedencia la dirección de cada entrada y su transacción de origen. Se construyen siempre desde la URL configurada; sin nodo, no hay enlace.

Corregido

  • El rastro de procedencia enlazaba a mempool.space público cuando no había nodo configurado (base ? … : "https://mempool.space/tx/…"). Un clic ahí le dice a un tercero qué transacción estás investigando, que es exactamente lo contrario de para lo que existe esta herramienta. Sin nodo ya no hay enlace: se muestra el txid en texto plano. Auditado que no queda ningún enlace saliente en toda la aplicación.
  • La fee mediana del detalle de bloque se mostraba con dieciséis decimales.

Nota de diseño

  • Se descartó hacer persistentes las etiquetas BIP-329. Vinculan direcciones con descripciones en lenguaje natural ("ahorro", "pago a…") y guardarlas dejaría en disco justo el mapa que un atacante querría. Que vivan solo en memoria no es una carencia, es la misma decisión que ya se aplica a la URL del nodo.

[1.13.0] — 2026-08-08

Cambiado

  • El checklist decía que un swap alto era "normal en nodos con índice completo". No lo es, y decirlo hace que se ignore durante semanas un síntoma con causa y con arreglo. El caso que lo cambió: swap al 99% con 18 GB de RAM libre, porque Fulcrum tenía db_mem a 16 GB — más de lo que cabe en la máquina junto al resto de servicios. Con el swap lleno el sistema se queda sin margen y, ante un pico, el OOM killer elige él a quién mata.
    • El umbral baja del 95% al 50%, que es cuando conviene mirarlo y no cuando ya es tarde, y pasa a estado de error por encima del 80%.
    • Si el swap sube teniendo RAM libre, el aviso lo señala: es la firma de un servicio con más memoria reservada de la que cabe, no de presión real.
    • Apunta al sospechoso habitual (db_mem de Fulcrum, que se sube para acelerar la sincronización inicial y es fácil olvidarse de bajar) e incluye el comando para ver qué proceso ocupa el swap.
  • Misma corrección en la explicación de SWAP de los DOCS.

Añadido

  • Nueva comprobación: direcciones que quedan vinculadas entre sí. Era el hueco de fondo del analizador: medía la privacidad desde el lado de quien construye la transacción (¿se ve mi cambio?, ¿pago cifras redondas?) y no desde el lado de los dueños de las monedas gastadas, que es donde el daño es irreversible. Gastar N direcciones distintas a la vez las enlaza para siempre por CIOH, y eso no se decía en ningún sitio. El peso sube con el número de direcciones y no aplica en CoinJoin, donde romper esa vinculación es el objetivo.

Corregido

  • El explorador mostraba saldo cero en direcciones con mucho historial. El backend de Mempool sobre Fulcrum devuelve los importes a cero cuando la dirección tiene muchas transacciones, aunque el contador venga bien — y la app los presentaba como ciertos. Una dirección con 492 transacciones aparecía con "Balance: 0,00000000 BTC". Ahora se detecta la inconsistencia (tener transacciones y no haber recibido nada es imposible en la cadena), los importes se muestran como "no disponible" y se explica por qué. El contador de transacciones y el historial, que sí son correctos, se mantienen.
  • Mismo arreglo en el perfil de dirección del peritaje: antes concluía "no es hot wallet" cuando en realidad no había podido evaluar la señal de flujo.
  • El fingerprinting atribuía transacciones a Electrum por AUSENCIA de rasgos (locktime 0, sin RBF, sequence por defecto). Es justo al revés: Electrum moderno pone locktime a la altura actual y señaliza RBF. Lo que esas señales describen no es un monedero concreto, sino software que no configura nada. Ahora Electrum exige señales positivas y aparece un resultado nuevo, "sin rasgos distintivos", que además no penaliza: no dejar huella es lo contrario de tener una huella identificable.

[1.12.1] — 2026-07-27

Corregido

  • El monitor mostraba una CPU por proceso que engañaba. La columna %CPU de ps aux no es el consumo actual sino la media desde que el proceso arrancó (tiempo de CPU dividido por tiempo de vida). Un proceso que trabajó mucho hace tres días seguía apareciendo alto para siempre, y se leía como si estuviera saturando la máquina. Se detectó porque los porcentajes por proceso no cambiaban NUNCA entre lecturas mientras la CPU global sí variaba.
    • Ahora se mide de verdad: dos lecturas de /proc/PID/stat separadas 500 ms, el mismo método que ya usaba getCpuUsage para el total. Las dos esperas corren en paralelo dentro del mismo Promise.all, así que no cuesta tiempo.
    • La interfaz muestra el porcentaje sobre el total de la máquina, que es lo que suele querer saberse, con el porcentaje de un núcleo y la media de ps en el tooltip para poder comparar con top.
    • Comprobado con carga artificial: el proceso ocupado marcaba 100% de un núcleo (25% de un sistema de 4) mientras ps daba 152%, imposible para un proceso de un solo hilo.

Cambiado

  • El UTXO Map pedía las transacciones de contexto con fetchWithTimeout directo, saltándose la caché añadida en la 1.11.0. Era el único punto que no la aprovechaba. Ahora pasa por get(), así que esas transacciones —ya confirmadas, e inmutables— se guardan toda la sesión.

Documentación

  • Reescrita la guía de instalación. SETUP.md no era una guía: más de la mitad eran los pasos personales de git y Gitea del autor ("PASO 1 — Crear el repo en Gitea"), que se han movido a un documento privado. Ahora es una guía real, con una comprobación tras cada paso para saber si vas bien sin descubrirlo al final con una pantalla en blanco.
  • Corregida la configuración de nginx documentada, que estaba rota. El README indicaba alias /var/www/txoko/dashboard.html — un alias a un ARCHIVO. Desde la 1.11.0, con las librerías en vendor/ y rutas relativas, eso hace que el navegador no las encuentre y la página quede en blanco sin ningún error visible. Debe apuntar al directorio. Es el fallo más común de esta instalación y ahora está avisado en tres sitios, con una comprobación concreta (curl mirando el content-type, no solo el código 200) para descartarlo.
  • Los pasos de instalación no mencionaban las librerías del frontend, sin las cuales la aplicación no arranca. Ya están integradas en el orden correcto.
  • Eliminados del repositorio los datos personales del autor: rutas de su máquina en la documentación y, sobre todo, su nombre de usuario del sistema y su ruta de instalación dentro de txoko-metrics.service, que llevaban ahí desde el primer commit. El servicio usa ahora marcadores que hay que ajustar antes de instalarlo.
  • README: estructura del repositorio actualizada (faltaban tests/, instalar-fuentes.sh y FIXTURES.md) y sección de instalación reducida a un resumen que remite a SETUP.md, para que haya una sola fuente de verdad.
  • SETUP.md incluye ahora tabla de problemas frecuentes y cómo actualizar.

[1.12.0] — 2026-07-27

Añadido

  • Auditoría de PSBT: revisar una transacción ANTES de firmarla. Hasta ahora toda la app era diagnóstico a posteriori — te contaba con detalle lo que ya había pasado y no podías cambiar. Esta es la primera pieza que llega a tiempo. Sustituye al antiguo "validador", que solo comprobaba que el archivo empezara por psbt y decía su tamaño.
    • Parser completo de BIP174 escrito desde cero, sin librerías, como el resto del proyecto. Validado contra los cinco vectores inválidos que publica el propio estándar: los rechaza los cinco, cada uno con un mensaje que explica en castellano qué está mal (truncada, sin salidas, ya firmada, sin transacción interna, con claves repetidas).
    • Todo el análisis es offline. Una PSBT bien formada ya lleva dentro los importes y scripts de sus entradas, así que no hace falta consultar el nodo: funciona con el nodo sincronizando, y el nodo ni se entera.
    • Acepta base64, hexadecimal o abrir el archivo .psbt directamente.
    • Aviso crítico sobre xpubs incrustados. Las PSBT suelen llevar dentro las claves públicas maestras de la cartera, y están hechas para compartirse — se mandan por correo o chat para que el resto firme. Quien reciba el archivo puede derivar todas las direcciones, presentes y futuras, y ver el saldo y el historial completos. No puede gastar, pero lo ve todo. Ningún wallet avisa de esto.
    • Detecta además: cambio identificable por tipo de dirección, importes redondos que delatan cuál es el pago, envíos a la propia cartera, carteras multifirma (con su M-de-N) y PSBTs incompletas sin los importes de entrada.
    • Cada aviso mantiene el formato del resto de la app — Hecho, Consecuencia y Qué puedes hacer —, que aquí cobra sentido literal: todavía estás a tiempo de cambiar la transacción.

Corregido

  • Revisión de la criptografía watch-only. Se verificó la derivación completa contra los vectores oficiales de los estándares: RIPEMD-160 (los seis del estándar, incluido el de un millón de caracteres), secp256k1, BIP32 (vectores 1 y 2) y bech32/BIP173. La matemática es correcta y no se tocó. Los fallos estaban en la validación de la entrada:
    • No se comprobaba la suma de verificación del xpub. Un carácter mal copiado se aceptaba sin protestar y generaba 200 direcciones ajenas: el usuario habría visto su cartera "sin actividad" y se habría quedado tranquilo. Falso negativo silencioso, el mismo patrón que el resto de fallos de esta jornada. Nuevo decodeBase58Check.
    • No se validaba la longitud del material decodificado (deben ser 78 bytes) ni que la clave pública fuese comprimida (0x02/0x03).
    • tpub se trataba como mainnet. La red se detectaba mirando si el texto empezaba por "tb", "u" o "v" — y un tpub, el formato más común de testnet, empieza por "t" pero no por "tb". Generaba direcciones bc1… a partir de claves de testnet. Ahora se detecta por bytes de versión, que son inequívocos, con las diez variantes (x/y/z/Y/Z y t/u/v/U/V).
    • deriveChildPubkey aceptaba índices endurecidos, matemáticamente imposibles desde una clave pública. No era alcanzable desde la interfaz, pero una función criptográfica debe defenderse sola.
  • Añadida la carpeta tests/ con las cuatro baterías y su documentación, incluido qué no cubren: no sustituyen una auditoría externa.

[1.11.0] — 2026-07-27

Añadido

  • Las librerías del frontend se sirven desde tu propio nodo. React, ReactDOM y Babel se cargaban desde unpkg.com, y las fuentes IBM Plex desde fonts.googleapis.com. Ninguno de los dos veía qué transacciones analizabas — pero ambos recibían tu IP pública, la hora y el referer en cada apertura del dashboard: sabían que usabas Txoko, cuándo y desde dónde. Ese metadato es justo lo que esta herramienta enseña a proteger. Ahora no sale ni una petición fuera de tu red, verificable con grep -E '(src|href)="https?://' dashboard.html (no devuelve nada).
    • Consecuencia práctica: el dashboard funciona sin conexión a internet.
    • Las librerías se descargan una vez durante la instalación y se verifican por hash (SHA-256 publicados en SETUP.md).
    • Versiones fijadas (react@18.3.1, @babel/standalone@7.23.10) en vez de rangos: antes el CDN decidía qué versión te entregaba y podía cambiar sin aviso.
    • instalar-fuentes.sh automatiza la descarga de IBM Plex (licencia OFL) y genera el CSS. Comprueba cada archivo y aborta si algo falla.
  • Caché de respuestas del nodo con TTL y coalescencia en useApi. Las pestañas se montan y desmontan al navegar, así que ir a otra pestaña y volver repetía todas las peticiones. Ahora:
    • Las transacciones confirmadas se cachean toda la sesión — son inmutables, no hay motivo para volver a pedirlas. Analizador, rastro de procedencia y peritaje dejan de pedir las mismas por separado.
    • Historial de direcciones 60 s, bloques 60 s, mempool y comisiones 20 s, estado del sistema 2 s (para que el monitor siga mostrando datos vivos).
    • Coalescencia: dos componentes que piden lo mismo a la vez generan una sola petición al nodo, no dos. Mismo patrón que ya usaba system-metrics.js en el servidor.
    • Medido: repetir un rastreo forense ya explorado cuesta cero peticiones.

Cambiado

  • Un hit de OFAC ya no penaliza la banda de privacidad. Era un error conceptual con consecuencias ideológicas: que tus monedas hayan pasado por una dirección sancionada no revela nada más sobre ti — tu privacidad es idéntica antes y después. Lo que cambia es la probabilidad de que un servicio regulado te bloquee un depósito, que es otro eje: censurabilidad, no privacidad. Restar puntos ahí equivalía a dar por buena la idea de "monedas contaminadas", justo la que la fungibilidad de Bitcoin niega. Se sigue informando del riesgo real, ahora como aviso de censura y con el contexto que faltaba: la lista OFAC es una decisión política de un gobierno concreto, no una determinación judicial, y fuera de su jurisdicción solo llega a través de intermediarios que la aplican.
  • RBF pasa a informativo, sin penalización. Es buena práctica —permite desatascar una transacción sin sobrepagar de entrada— y hoy lo activan casi todos los wallets, así que distingue poco. Restar puntos empujaba al usuario hacia una decisión peor para esconder una señal débil.
  • Checks con inferencia fuerte (round_numbers, unnecessary_input, output_type_mismatch) reescritos con el patrón Hecho / Interpretación / Consecuencia que ya usaban dust e input_type_mixing. Antes afirmaban de más ("un analista puede identificarlo sin ambigüedad"); ahora explican cuándo la señal falla y por qué son PROBABLE y no CERTEZA.
  • timing: el texto didáctico describía patrones entre varias transacciones cuando el check solo ve una. Además se aclara que la hora mostrada es la del bloque, no la de la firma — entre ambas puede haber horas de mempool.

Documentación

  • README: nueva sección "Sí, esto es chain analysis". El peritaje usa las mismas técnicas que las empresas de vigilancia de cadena y negarlo restaba credibilidad ante quien lee el código. Se explica qué cambia —quién lo ejecuta, sobre qué, dónde se detiene, quién se queda el informe— y el motivo de fondo: la misma herramienta que sigue el rastro de un ladrón demuestra lo fácil que es seguir el tuyo.
  • El informe forense advierte del coste de denunciar: entregarlo vincula tu identidad legal con esas direcciones de forma permanente, ante una autoridad que puede compartir el expediente con empresas de análisis. Antes se recomendaba denunciar sin mencionar el precio.
  • Aviso junto a los botones de exportación: el archivo lleva tus direcciones y tu declaración dentro. Nada ha salido de tu red hasta ese punto; a partir de ahí depende de quien lo descarga.
  • Corregido "un único archivo HTML autocontenido" (aparecía cuatro veces): desde la 1.11.0 las librerías viven en vendor/. Se sustituye por una descripción exacta que además dice más — lo que lees en el archivo es lo que se ejecuta, no hay versión compilada que auditar por separado.

Corregido

  • El informe ya no atribuye al actor direcciones del otro lado de un CoinJoin. Detectado probando un rastro que atraviesa un Whirlpool real: el informe declaraba "el rastro se rompe en un CoinJoin — no se puede atribuir con honestidad más allá de este punto" y, tres líneas más abajo, listaba 10 direcciones atribuidas al actor, cinco de ellas salidas de esa misma mezcla. Eran direcciones de otros participantes, señaladas en un documento pensado para acompañar una denuncia.

    • Los dos fundamentos que las colaban fallan precisamente ahí: CIOH asume que quien gasta varios inputs juntos los controla, y un CoinJoin existe para romper esa suposición (es la excepción clásica a la heurística); y la huella de software sale estable por construcción, porque todos los participantes usan el mismo programa.
    • finalizeForensicGraph excluye ahora las transacciones marcadas como mixer del conjunto de direcciones del actor y del union-find, y la atribución por huella salta esos nodos.
    • Verificado con el mismo caso: de 10 direcciones atribuidas a 0.
  • El informe de wallet ya no da un aprobado optimista cuando faltan datos. Mismo patrón que el fallo del peritaje, en la pieza central del proyecto: scanWallet usaba .catch(()=>[]) en las tres consultas del escaneo, así que una dirección que el nodo no pudo servir quedaba indistinguible de una dirección sin actividad. Sus transacciones no se traían, no contaban para la reutilización, no entraban en el union-find y no aparecían en el historial — y el informe daba su valoración de salud sin mencionar que le faltaban datos. El sesgo iba siempre hacia el optimismo: menos actividad vista es mejor nota.

    • Las tres consultas usan ahora getStrict y registran los fallos en report.scanErrors, con la dirección, la rama y en qué fase ocurrió.
    • Aviso en rojo antes de la banda de salud (una valoración leída sin saber que faltan datos es peor que ninguna valoración), y bloque equivalente al principio del export Markdown.
  • Tampoco atribuye al actor las direcciones de un custodio. Misma raíz que el fallo anterior, descubierta probando la poda por rama con un depósito real en Bitfinex: el cluster CIOH ya excluía las direcciones de custodio, pero la atribución por huella de software no, así que la hot wallet del exchange acababa listada como "dirección del actor" mientras la conclusión, dos líneas más abajo, la identificaba correctamente como Bitfinex. La dirección donde el ladrón deposita es del exchange, no del ladrón. Ambos criterios están ahora alineados: ni mezclas ni custodios entran por ninguna de las dos vías. Verificado: de 2 direcciones atribuidas a 1 (solo la rama legítima).


[1.10.1] — 2026-07-27

Añadido

  • Tope de ramificación en el peritaje (MAX_FANOUT, 25 salidas). Detectado probando el fixture de dust attack: una transacción que reparte a cientos de direcciones hacía que el motor encolara todas sus ramas y, sobre todo, que perfilara cada dirección de salida — 2 peticiones por dirección, así que una tx de 143 salidas suponía ~286 peticiones al nodo antes siquiera de llegar al frontier, y la pestaña se congelaba. Ahora, por encima del tope, la tx se trata como reparto masivo (dust attack, lote de retiradas, airdrop): se corta ANTES de perfilar nada, con stopReason: "fanOut" y su propia conclusión en el informe, redactada como límite deliberado y no como inferencia sobre quién controla esas direcciones. Verificado con una tx real de 143 salidas: 2 peticiones en total.

Corregido

  • Peritaje forense: un fallo de consulta ya no se presenta como "rastro completo". Detectado probando contra el nodo real: cuando el backend devolvía un 503 o agotaba el timeout, la app lo mostraba como "✓ Rastro completo — no quedan ramas por explorar" y contaba esa rama como terminal. La causa eran dos capturas silenciosas encadenadas — get devolvía mockData ante cualquier error y findSpendingTx remataba con .catch(()=>[]) —, así que [] por error era indistinguible de [] porque el output sigue sin gastar. En un informe pericial eso convertía una consulta fallida en la conclusión más accionable del documento: fondos localizados sin gastar.
    • Nuevo getStrict en useApi: propaga el fallo en vez de disfrazarlo. get no cambia, así que el resto del dashboard mantiene su comportamiento.
    • El motor (findSpendingTx, advanceForensicHop, initForensicTrace) distingue "no se pudo consultar" de "no hay gasto" y registra los fallos en trace.queryErrors.
    • El informe excluye las ramas con consulta fallida de "fondos localizados sin gastar", las lista en su propia sección y abre las conclusiones avisando de que el rastreo está incompleto. Incluido en los export JSON y MD.
    • La UI muestra contador de consultas fallidas y sustituye el falso "rastro completo" por un aviso con el detalle de qué falló.
  • Peritaje: el error al obtener la transacción de origen ya no culpa siempre al txid — distingue un txid inexistente de un fallo del nodo.
  • Peritaje: el botón "Generar informe" explica por qué está deshabilitado en vez de quedarse inerte sin dar motivo.

Cambiado

  • El aviso de consulta fallida ya no dice que el fallo "suele ser transitorio": cuando se repite sobre la misma dirección no lo es, y ahora lo explica — historial demasiado pesado para servirlo dentro del tiempo de espera, con la indicación de comprobarla a mano antes de dar el rastro por cerrado.

Documentación

  • README: documentadas dos limitaciones reales del peritaje — las ramas que no se pueden comprobar (y por qué cortar es deliberado, no un defecto), y que el tope de volumen mide número de transacciones y no peso, así que una dirección con pocas transacciones muy grandes puede agotar el tiempo de espera igual.

[1.10.0] — 2026-07-16

Añadido

  • Peritaje forense: nueva pestaña que rastrea fondos robados o perdidos hacia adelante, salto a salto, desde una transacción de origen (txid:vout) hasta un punto de parada natural — custodio identificado, dilución excesiva, CoinJoin real, o fondos aún sin gastar. Todo el rastreo corre sobre tu propio nodo (Bitcoin Core + Fulcrum + Mempool self-hosted), como el resto de la app: ninguna consulta sale de tu red.
    • Sigue todos los outputs de cada salto (no solo el presunto cambio), porque los fondos pueden repartirse en varias ramas; cada rama se detiene de forma independiente.
    • A demanda, salto a salto: el rastreo no corre solo — tú decides cuándo se explora el siguiente salto con el botón "Seguir el rastro", viendo en todo momento cuántas transacciones se han explorado y cuántas ramas quedan pendientes. Mismo espíritu que el rastro de procedencia hacia atrás (RastroProcedencia), aplicado al rastreo hacia adelante. Puedes generar el informe con lo explorado hasta ese momento, sin necesidad de terminar el rastreo entero.
    • Tope de volumen de transacciones (tx_count) como cinturón de seguridad aparte del control manual: si una dirección de salida tiene un historial extremadamente largo (miles de transacciones — típico de un hot wallet de exchange), el rastro se detiene ahí por precaución aunque el heurístico de perfil no la clasifique como custodio. Evita que una sola rama intente paginar el historial completo de una dirección con decenas de miles de transacciones.
    • Reutiliza las heurísticas existentes del analizador (CIOH, detección de cambio estructural, huella de wallet, CoinJoin, entidades conocidas) y añade tres nuevas: perfil de dirección (personal vs hot wallet de exchange), cambio conductual (se gasta rápido vs queda quieto) cruzado con la señal estructural, y comparación de huella de software entre saltos consecutivos.
    • Confirma cadenas de peeling multi-salto: el check de patrón de pago simple ya avisaba de que una sola transacción no basta para confirmar una cadena — este módulo es lo que cierra ese hueco, siguiendo el rastro hacia adelante de verdad.
    • Marco de tres niveles en cada afirmación del informe: HECHO (dato on-chain verificable), INFERENCIA (conclusión de una heurística, con su propia sub-etiqueta CERTEZA/PROBABLE/POSIBLE) y DECLARACIÓN (lo que cuenta el afectado, en un formulario de texto libre, siempre mostrado aparte y nunca mezclado con los hechos).
    • Informe con resumen, declaración del afectado, cronología, direcciones atribuidas con su fundamento, fondos localizados sin gastar, conclusiones numeradas, recomendaciones (con un aviso fijo contra estafas de "recuperación de fondos" siempre que hay declaración), metodología y anexo de verificación. Exportable a JSON y Markdown, igual que el informe de wallet.
    • No identifica la identidad real de nadie: como mucho llega a "hot wallet de [exchange]" o "custodio no identificado". No hace denuncias ni envíos automáticos a terceros — el informe es un documento que decides tú a dónde llevar.

Cambiado

  • unionFindCluster (vinculación por CIOH) y guessChangeOutput (señales de cambio estructural) se extrajeron de buildWalletReport y analyzeTx respectivamente a funciones compartidas, sin cambio de comportamiento, para que el peritaje forense las reutilice salto a salto.

[1.9.0] — 2026-06-12

Añadido

  • Informe de wallet completo. Tras cargar tu xpub (watch-only), el botón "Analizar wallet" examina el conjunto de tus transacciones y produce un informe con tres partes: salud general (ALTA/MEDIA/BAJA según reutilización de direcciones y vinculación), clusters de vinculación detectados por la heurística CIOH (common-input-ownership: direcciones que gastaste juntas y que un observador asume del mismo dueño), e historial de cada transacción con su banda de privacidad. Exportable a JSON y Markdown. Es la visión de conjunto que ningún explorador ofrece: no analiza una transacción aislada, sino qué puede agrupar un observador de toda tu actividad. El escaneo se hace por lotes con pausas para no saturar el nodo, y todo el cálculo ocurre en el navegador.
  • Presentación de resultados reorganizada. El informe de privacidad ahora abre con un resumen ("N señales a revisar · M correctas · K informativas"), mantiene los problemas siempre visibles y agrupa las señales correctas e informativas en secciones colapsables. Al desplegar un problema, la explicación didáctica aparece directa, con una línea "Qué puedes hacer" según el caso (ya está en la cadena / depende de tu wallet / puedes evitarlo al construir la transacción).

Cambiado

  • Las recomendaciones usan un lenguaje más claro y menos técnico: "depende del wallet" y "puedes evitarlo" en lugar de etiquetas crípticas. El peso de cada señal en la banda se describe como alto/medio/bajo en vez de un número.

Corregido

  • El monitor del sistema (system-metrics.js) ya no usa la librería express: ahora funciona solo con Node.js, sin dependencias ni npm install. Descargar y ejecutar. Esto elimina el error "Cannot find module 'express'" que veían los usuarios nuevos.
  • Los nombres de proceso en "Procesos destacados" se muestran limpios: un servicio Node con flags (p.ej. Mempool con --max-old-space-size) aparece como "node (index.js)" en vez de mostrar el argumento crudo.
  • La medición de CPU del monitor usa una ventana de 500ms para una lectura más estable y coherente con la de herramientas como top.

[1.8.0] — 2026-06-04

Añadido

  • Importación de etiquetas BIP-329. Permite cargar el archivo .jsonl que exporta Sparrow (File → Export → Export Labels) para ver tus propias etiquetas junto al análisis. El archivo se lee en memoria del navegador y no sale del nodo. La etiqueta de la transacción analizada aparece de forma destacada bajo el txid, y el modal lista todas las etiquetas cargadas (referencia + etiqueta) para verificar lo que tienes importado.
  • Watch-only por clave pública extendida (xpub/zpub). Pegando el Master Public Key de Sparrow, Txoko deriva tus direcciones de recepción y cambio en local y marca automáticamente, en cada transacción analizada, qué outputs son tuyos: recepción (verde) o cambio (ámbar), con su valor y etiqueta. Es lo que ningún explorador público puede decirte, porque no conoce tus direcciones. Toda la derivación (BIP32 + bech32) está implementada desde cero con las primitivas del navegador (Web Crypto API), sin librerías externas, fiel a la filosofía de código auditable. El xpub nunca sale del navegador.
  • Selector del número de direcciones a derivar (20 / 50 / 100 por rama). Más direcciones dan más cobertura para wallets muy usados, a cambio de unos segundos más de cálculo. Se muestran las tres primeras direcciones derivadas para que el usuario verifique, comparándolas con Sparrow, que ha cargado el wallet correcto.
  • Estado "Dirección sin usar" en el análisis de direcciones. Una dirección sin historial on-chain ya no se muestra como "privacidad aceptable" (que sugería erróneamente que era buena), sino como dirección nueva sin nada que analizar.

Cambiado

  • El informe de privacidad usa el sustantivo correcto ("dirección" o "transacción") según lo que se esté analizando, en lugar de decir siempre "transacción".

Corregido

  • Corregida la aritmética de curva secp256k1 usada en la derivación watch-only. El inverso modular por el algoritmo de Euclides extendido fallaba en ciertos casos con enteros grandes, y la suma de puntos no manejaba el caso punto más su inverso. Las operaciones pequeñas (2G, 3G) salían bien pero la derivación de direcciones reales producía resultados incorrectos. Resuelto usando el inverso por el pequeño teorema de Fermat y completando los casos de la suma de puntos. Verificado contra los vectores de prueba estándar de RIPEMD-160, bech32 (BIP173) y secp256k1, y contra la identidad de grupo.

[1.7.0] — 2026-06-04

Añadido

  • Detección de CoinJoin estructural (WabiSabi y similares). El motor reconocía CoinJoin por denominaciones fijas (Whirlpool) o por outputs de igual valor (CoinJoin genérico), pero no capturaba WabiSabi, que usa outputs de valor variable. Se añadió una tercera variante: detecta mezclas por forma estructural (muchos inputs y outputs, ratio cercano a 1, sin output dominante). El fingerprint "Wasabi o JoinMarket" se activa también para esta variante.

  • Check de datos OP_RETURN en el motor de privacidad. Hasta ahora OP_RETURN solo se detectaba en la herramienta dedicada de TOOLS. Ahora aparece en el informe de privacidad de Auditoría: informa de cuántos outputs OP_RETURN hay y su tamaño en bytes, sin mostrar el contenido. Una transacción con OP_RETURN fuerza banda BAJA independientemente del resto de señales.

  • Check de tipo de script legacy (P2PKH/P2SH). Detecta cuando los inputs usan direcciones legacy (1... o 3...) en lugar de SegWit (bc1q...) o Taproot (bc1p...). Informa de que forman un conjunto de usuarios cada vez más pequeño, lo que reduce el anonimato por conjunto. Peso 15, certeza CERTEZA, actionability "wallet" (depende del software).

Cambiado

  • En transacciones CoinJoin, los checks "Mezcla de tipos de script en inputs", "Inputs innecesarios (consolidación revelada)" y "Fingerprinting de wallet" ahora se muestran como informativos (punto gris, sin penalización) en lugar de como advertencias en rojo. En una mezcla, estas condiciones son esperadas por diseño del protocolo — no son fallos del usuario.

Corregido

  • El check de batch payment ya no dispara en transacciones WabiSabi. Al no detectarse como CoinJoin, el filtro !likelyCJ no se activaba y un WabiSabi de 327×279 aparecía marcado como batch. Resuelto al corregir la detección.

[1.6.0] — 2026-06-03

Añadido

  • Detección de exchanges (cuarta categoría de entidad, junto a OFAC, minería y CoinJoin). Cuando una transacción o un eslabón del rastro toca una dirección asociada a un exchange conocido, se marca con 🏦 y aparece en el veredicto y en la distancia a entidad del rastro.
  • La detección distingue la fiabilidad de cada dirección según su origen, en línea con la honestidad del resto de la herramienta:
    • Direcciones que el propio exchange ha publicado, o de etiquetas públicas conocidas, se muestran como coincidencia (certeza PROBABLE).
    • Direcciones inferidas por agrupación (clustering) se muestran como "posible" (certeza POSIBLE), avisando claramente de que es una inferencia estadística no confirmada por el exchange y de que puede haber falsos positivos.
  • Conjunto inicial de ~590 direcciones de 16 exchanges, mayoritariamente de datos de agrupación pública, etiquetadas con su fuente para reflejar su fiabilidad.

[1.5.0] — 2026-06-03

Cambiado

  • Mejoras de legibilidad del rastro de procedencia, para interpretar los datos de un vistazo:
    • Veredicto arriba del rastro: "Camino limpio" (en verde) si nada de lo explorado toca entidades marcadas, o "Atención" (en ámbar) indicando qué toca y a cuántos saltos. Responde de un vistazo si hay algo que revisar.
    • Jerarquía visual: los eslabones con buena privacidad y sin marcas se muestran discretos; los que merecen atención (marca o banda no alta) se destacan con color. El ojo va directo a lo relevante.
    • Barra visual de cantidad en cada eslabón, para captar la proporción sin leer la cifra; el número queda al lado como apoyo.
    • Indicador de estructura (entradas → salidas) siempre visible junto a cada eslabón, útil para detectar consolidaciones grandes de un vistazo.
    • Detalle ampliado al pasar el ratón (o tocar en móvil) sobre el indicador de estructura: número exacto de entradas y salidas, valor en sat y BTC, bloque, comisión y tasa. Mantiene la vista limpia y el detalle a mano.
  • Contraste de texto mejorado en toda la aplicación. El texto secundario (descripciones, datos de apoyo, el texto dentro de las casillas y el pie de página) era demasiado tenue y costaba leerlo. Se ha subido su contraste en los cuatro temas, manteniendo la jerarquía visual: el texto secundario se sigue distinguiendo del principal, pero ahora se lee con comodidad.

[1.4.0] — 2026-06-02

Añadido

  • Distancia a una entidad en el rastro de procedencia. A medida que se exploran eslabones, un resumen arriba del rastro indica a cuántos saltos está lo más cercano de cada tipo marcado (OFAC, minería, CoinJoin) — por ejemplo "minería · a 2 saltos". Es honesto sobre su alcance: solo cuenta las ramas que se han seguido y avisa de que puede haber más sin explorar.

Corregido

  • Transacciones coinbase como origen del rastro. Antes mostraban un aviso confuso ("este input no indica su transacción de origen"), como si fuera un error. Ahora se reconocen como el principio natural del rastro: un mensaje claro indica que esas monedas se crearon ahí como recompensa de minado y no proceden de ninguna transacción anterior.

[1.3.0] — 2026-06-02

Añadido

  • Rastro de procedencia. En la pestaña Auditoría, debajo del informe de privacidad, cada input de la transacción tiene un botón "seguir rastro" que trae su transacción de origen y muestra un eslabón con: el txid de origen (enlace a tu propio Mempool), cuánto fluyó, la fecha, la banda de privacidad de esa transacción y marcas relevantes (CoinJoin, OFAC, minería, coinbase).
  • El rastro es recursivo: desde cada eslabón se puede seguir bajando por sus propios inputs, encadenando saltos hacia atrás nivel a nivel. Funciona bajo demanda —cada consulta la pide el usuario, para no sobrecargar el nodo— y comparte una caché en memoria para no repetir transacciones ya consultadas. Incluye un límite de profundidad y un botón para limpiar el rastro.

Corregido

  • Detección de CoinJoin en el rastro: antes marcaba como CoinJoin cualquier transacción cuyo análisis mencionara la palabra (lo que ocurría siempre, porque existe un indicador con ese nombre aunque dé negativo), produciendo falsos positivos. Ahora la marca solo aparece cuando el indicador de CoinJoin da positivo de verdad (estructura de varios inputs y salidas de igual valor).

[1.2.1] — 2026-06-02

Cambiado

  • La herramienta de OP_RETURN pasa de decodificar y mostrar el contenido a solo detectar su presencia y tamaño. Para auditar privacidad, lo relevante es que una transacción contenga datos arbitrarios (revela uso de un protocolo o servicio), no qué dicen esos datos. Además, la herramienta no debe funcionar como visor de contenido arbitrario de la cadena. Ahora indica cuántos outputs OP_RETURN hay y su tamaño en bytes, sin mostrar el contenido.

[1.2.0] — 2026-06-01

Añadido

  • Exportación del informe de privacidad de una transacción en dos formatos, desde la pestaña Auditoría. El botón "↓ JSON" descarga el análisis completo con su estructura (score, banda, wallets detectados y todas las señales con su detalle), pensado para procesar con scripts o archivar en formato máquina. El botón "↓ MD" descarga el informe legible en Markdown (diagnóstico, qué puede saber un analista, limitaciones, recomendaciones y una tabla de señales), para leer o guardar como documento. Ambos se generan en el navegador y se descargan en local — no sale nada del nodo.

Corregido

  • El botón "Analizar privacidad" del Lab ahora envía correctamente el txid a la pestaña Auditoría y lanza el análisis. Antes la pestaña aparecía vacía porque el identificador no se transmitía entre vistas.

[1.1.0] — 2026-06-01

Añadido

  • Exportación del UTXO Map a CSV. Un botón "↓ CSV" en el UTXO Map descarga todos los UTXOs de la dirección analizada con su información: txid, vout, valor en sats y en BTC, estado de confirmación, altura de bloque, score de privacidad y problemas detectados. El archivo se genera en el navegador y se descarga en local — no pasa por ningún servidor, no sale nada del nodo. Pensado para abrir en una hoja de cálculo y ordenar o filtrar los UTXOs por privacidad.

1.0.0 — 2026-05-31

Primera versión completa y funcional. Suite de auditoría de privacidad Bitcoin self-hosted, con motor de análisis, exploración de cadena, monitor del nodo y detección de entidades.

Motor de análisis de privacidad

  • Análisis de transacción con 15+ heurísticas ponderadas
  • Score de privacidad por bandas (ALTA / MEDIA / BAJA), sin precisión numérica falsa
  • Informe narrativo en prosa: explica qué puede deducir un observador
  • Distinción explícita entre certeza, probabilidad y posibilidad en cada señal
  • Etiquetas de accionabilidad: qué es evitable, qué depende del wallet, qué ya está en la cadena y no se puede cambiar

Detección de CoinJoin

  • Whirlpool con denominaciones fijas y tolerancia del 2%
  • CoinJoin genérico por outputs de igual valor
  • Filtro de denominación mínima (10.000 sats) — descarta mezclas de polvo que no son CoinJoin reales
  • OP_RETURN tratado correctamente: un Whirlpool con OP_RETURN de cambio se sigue detectando
  • Supresión de penalizaciones coherente: en una mezcla no penaliza señales que son esperadas

Fingerprinting de wallet

  • Detección de BlueWallet, Bitcoin Core, Sparrow, Electrum y wallets con Taproot nativo a partir de señales estructurales combinadas
  • Wallet inferido del tipo de CoinJoin (Whirlpool → Samourai/Sparrow, genérico → Wasabi/JoinMarket)
  • En CoinJoin el fingerprinting es informativo y no penaliza

Detección de entidades

  • Índice de ~155 direcciones embebido, lookup local sin consultas externas
  • OFAC: alerta crítica si una dirección está en la lista de sanciones (Blender.io, Sinbad, Garantex, Suex, Chatex, Lazarus Group)
  • Mining pools: marca informativa de origen en pool de minería (F2Pool, Foundry, Antpool, MARA, Braiins, Luxor, Ocean, NiceHash, Bitfury)

Exploración y monitor

  • Explorador de bloques y búsqueda on-chain
  • Vista de Mempool con stats, fees y bloques proyectados
  • Monitor del nodo: estado de Bitcoin Core, sistema y logs en tiempo real
  • UTXO Map con score de privacidad por moneda
  • Herramientas: conversor de unidades, validador de dirección, decodificadores

Experiencia de uso

  • El análisis se mantiene al cambiar de pestaña y volver (Privacy Lab y Auditoría) — el estado vive en memoria, sin escribir en disco
  • Diseño responsive para móvil
  • Tema cypherpunk

Filosofía

  • Sin dependencias externas de datos: todo viene del propio nodo del usuario
  • Ninguna consulta sale de la red del usuario
  • Didáctica honesta sobre las limitaciones del análisis