Files
txoko-dashboard/CHANGELOG.md
T
Aitor b579a0653a docs: reescribir la guía de instalación, que llevaba a una app rota
SETUP.md no era una guía de instalación: más de la mitad eran los pasos
personales de git y Gitea del autor. Se mueven a un documento privado.

Y lo importante: la configuración de nginx documentada en el README estaba
rota desde la 1.11.0. Indicaba un alias a dashboard.html (un ARCHIVO), pero
con las librerías en vendor/ y rutas relativas eso deja al navegador sin
encontrarlas — página en blanco y ningún error visible. Debe ser un alias al
DIRECTORIO. Quien siguiera el README al pie de la letra no conseguía arrancar.

Ahora hay una guía real con comprobación tras cada paso, incluida la que
descarta ese fallo concreto: curl mirando el content-type, no solo el 200.
Se añaden las librerías al flujo (faltaban, y sin ellas no arranca), se quitan
las rutas personales y se actualiza la estructura del repo.
2026-07-27 16:38:48 +02:00

674 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
Todos los cambios notables de Txoko Node Dashboard se documentan aquí.
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/)
y el versionado sigue [Versionado Semántico](https://semver.org/lang/es/):
`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.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
[1.0.0]: https://git.bitcointxoko.org/pikaro/txoko-dashboard