El informe decía 'el rastro se rompe en un CoinJoin, no se puede atribuir con
honestidad más allá de este punto' y acto seguido listaba 10 direcciones
atribuidas al actor, cinco de ellas salidas de esa misma mezcla — es decir,
de otros participantes, señalados en un documento para una denuncia.
CIOH no aplica dentro de un CoinJoin (es su excepción clásica: la mezcla
existe para romper la suposición de dueño común) y la huella de software sale
estable por construcción, porque todos usan el mismo programa.
finalizeForensicGraph excluye las tx marcadas como mixer del conjunto del
actor y del union-find; la atribución por huella salta esos nodos.
Verificado contra el nodo con un Whirlpool real: de 10 atribuciones a 0.
Las librerías (React, Babel) venían de unpkg.com y las fuentes de Google.
Ninguno veía qué transacciones analizabas, pero ambos recibían tu IP y la hora
en cada apertura: sabían que usabas Txoko, cuándo y desde dónde — el metadato
que la propia herramienta enseña a proteger. Ahora se sirven desde el nodo,
con verificación por hash y versiones fijadas. El dashboard funciona sin
internet.
Además, caché con TTL y coalescencia en useApi: las transacciones confirmadas
son inmutables y se cachean toda la sesión, así que repetir un análisis ya
explorado no cuesta ninguna petición al nodo (medido).
Una tx con cientos de salidas (dust attack, lote de retiradas, airdrop) hacía
que el motor perfilara cada dirección de salida (2 peticiones cada una) antes
de encolar las ramas: ~286 peticiones para una tx de 143 salidas, con la
pestaña congelada. El tope corta antes de perfilar, que es donde está el coste.
Verificado contra el nodo con una tx real de 143 salidas: 2 peticiones.
- el aviso ya no promete que el fallo es transitorio: cuando se repite sobre
la misma dirección no lo es, y ahora dice por qué y qué hacer
- README: las ramas no comprobadas quedan fuera de 'fondos sin gastar' a
propósito — cortar protege el nodo y una consulta fallida no es una
conclusión
- README: el tope de volumen mide número de tx, no peso; una dirección con
pocas transacciones muy grandes puede agotar el tiempo de espera igual
(visto con una de 59 tx de ~15 KB)
Detectado probando contra el nodo real: un 503 del backend se mostraba como
'Rastro completo' y contaba la rama como terminal, porque get() devolvía
mockData ante cualquier error y findSpendingTx remataba con .catch(()=>[]).
Un error de red quedaba así indistinguible de 'output sin gastar' — la
conclusión más accionable de un informe pericial, afirmada sobre una consulta
que nunca respondió.
- getStrict en useApi propaga el fallo; get se mantiene igual para el resto
- el motor registra los fallos en trace.queryErrors y no los cuenta como
fondos sin gastar
- el informe los lista aparte y abre las conclusiones avisando del alcance
incompleto (UI, JSON y MD)
- la UI muestra el detalle del fallo en vez del falso rastro completo
Refleja el cambio de modelo del peritaje forense: de "automático
acotado con seguir más saltos" a "a demanda, salto a salto, con
control manual del usuario", más el tope de tx_count como cinturón
de seguridad adicional. El mecanismo antiguo "seguir más saltos (+4)"
ya no existe en el código — se documenta el que lo reemplaza.
CHANGELOG (1.10.0) y README reflejan que el peritaje forense ya está
implementado, no solo especificado: qué hace, qué heurísticas reutiliza
y cuáles son nuevas, el marco HECHO/INFERENCIA/DECLARACION, y la
limitación conocida de depender de /api/address/{addr}/txs en vez de
/outspend (el backend Mempool self-hosted no lo expone).