Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -56,10 +56,15 @@ def analizar_transaccion(tx_id):
|
|
56 |
"""
|
57 |
Analiza una transacción Bitcoin:
|
58 |
- Obtiene los datos.
|
59 |
-
- Aplica una heurística
|
60 |
- Genera un grafo interactivo.
|
61 |
- Retorna un reporte en HTML y la figura del grafo.
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
63 |
"""
|
64 |
tx_data = get_transaction(tx_id)
|
65 |
if not tx_data:
|
@@ -73,8 +78,14 @@ def analizar_transaccion(tx_id):
|
|
73 |
montos = [out.get("value", 0) / 1e8 for out in tx_data.get("vout", [])]
|
74 |
montos_unicos = len(set(montos))
|
75 |
|
76 |
-
|
|
|
|
|
|
|
77 |
|
|
|
|
|
|
|
78 |
# Generar grafo
|
79 |
G = generar_grafo(tx_data)
|
80 |
pos = nx.spring_layout(G, seed=42)
|
@@ -131,6 +142,19 @@ def analizar_transaccion(tx_id):
|
|
131 |
confirmed = status.get("confirmed", False)
|
132 |
estado_confirmacion = "Confirmada" if confirmed else "No confirmada"
|
133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
reporte = f"""
|
135 |
<div style="padding: 20px; background: #1a1a1a; border-radius: 10px; color: white;">
|
136 |
<h3 style="color: {'#FF5252' if es_mixer else '#4CAF50'};">
|
@@ -139,9 +163,16 @@ def analizar_transaccion(tx_id):
|
|
139 |
<p><strong>TXID:</strong> {tx_id}</p>
|
140 |
<p>📥 Inputs: {num_inputs}</p>
|
141 |
<p>📤 Outputs: {num_outputs}</p>
|
142 |
-
<p>💰 Montos únicos: {montos_unicos}</p>
|
|
|
|
|
|
|
143 |
<p>📅 Fecha: {fecha_str}</p>
|
144 |
<p>🔔 Estado: {estado_confirmacion}</p>
|
|
|
|
|
|
|
|
|
145 |
</div>
|
146 |
"""
|
147 |
|
@@ -164,7 +195,7 @@ with gr.Blocks(theme=gr.themes.Soft(), title="🔍 Detector de Mixers en Transac
|
|
164 |
gr.Markdown("### Ejemplos de TXIDs válidos:")
|
165 |
gr.Examples(
|
166 |
examples=[
|
167 |
-
["
|
168 |
["a83926f2fba1e446c0d5731a6866e78730fc3e21e31207fc0a3ee56e752843e9"]
|
169 |
],
|
170 |
inputs=tx_input
|
|
|
56 |
"""
|
57 |
Analiza una transacción Bitcoin:
|
58 |
- Obtiene los datos.
|
59 |
+
- Aplica una heurística para detectar posibles mixers.
|
60 |
- Genera un grafo interactivo.
|
61 |
- Retorna un reporte en HTML y la figura del grafo.
|
62 |
+
|
63 |
+
Se añaden datos forenses adicionales, como:
|
64 |
+
- Totales en BTC de entradas y salidas.
|
65 |
+
- Fee de la transacción.
|
66 |
+
- Análisis de indicadores (cantidad de inputs/outputs, montos únicos).
|
67 |
+
Nota: Este analizador se basa en heurísticas y se recomienda un análisis manual adicional.
|
68 |
"""
|
69 |
tx_data = get_transaction(tx_id)
|
70 |
if not tx_data:
|
|
|
78 |
montos = [out.get("value", 0) / 1e8 for out in tx_data.get("vout", [])]
|
79 |
montos_unicos = len(set(montos))
|
80 |
|
81 |
+
# Cálculos forenses adicionales: totales y fee
|
82 |
+
total_input_value = sum(inp.get("prevout", {}).get("value", 0) for inp in tx_data.get("vin", [])) / 1e8
|
83 |
+
total_output_value = sum(out.get("value", 0) for out in tx_data.get("vout", [])) / 1e8
|
84 |
+
fee = total_input_value - total_output_value
|
85 |
|
86 |
+
# Indicador de posible mixer según heurística simple.
|
87 |
+
es_mixer = num_inputs > 5 and num_outputs > 5 and montos_unicos < 3
|
88 |
+
|
89 |
# Generar grafo
|
90 |
G = generar_grafo(tx_data)
|
91 |
pos = nx.spring_layout(G, seed=42)
|
|
|
142 |
confirmed = status.get("confirmed", False)
|
143 |
estado_confirmacion = "Confirmada" if confirmed else "No confirmada"
|
144 |
|
145 |
+
# Mensaje según el análisis
|
146 |
+
if es_mixer:
|
147 |
+
mensaje_mixer = (
|
148 |
+
"<p style='color: #FF5252;'><strong>Alerta de Mixer:</strong> "
|
149 |
+
"La transacción presenta patrones compatibles con un servicio de mezcla "
|
150 |
+
"(muchos inputs/outputs y pocos montos únicos). Se recomienda un análisis forense adicional.</p>"
|
151 |
+
)
|
152 |
+
else:
|
153 |
+
mensaje_mixer = (
|
154 |
+
"<p style='color: #4CAF50;'><strong>Sin indicios de mezcla:</strong> "
|
155 |
+
"La transacción no muestra patrones comunes asociados a servicios mixer.</p>"
|
156 |
+
)
|
157 |
+
|
158 |
reporte = f"""
|
159 |
<div style="padding: 20px; background: #1a1a1a; border-radius: 10px; color: white;">
|
160 |
<h3 style="color: {'#FF5252' if es_mixer else '#4CAF50'};">
|
|
|
163 |
<p><strong>TXID:</strong> {tx_id}</p>
|
164 |
<p>📥 Inputs: {num_inputs}</p>
|
165 |
<p>📤 Outputs: {num_outputs}</p>
|
166 |
+
<p>💰 Montos únicos en outputs: {montos_unicos}</p>
|
167 |
+
<p>💵 Total Entradas: {total_input_value:.8f} BTC</p>
|
168 |
+
<p>💸 Total Salidas: {total_output_value:.8f} BTC</p>
|
169 |
+
<p>🧾 Fee: {fee:.8f} BTC</p>
|
170 |
<p>📅 Fecha: {fecha_str}</p>
|
171 |
<p>🔔 Estado: {estado_confirmacion}</p>
|
172 |
+
{mensaje_mixer}
|
173 |
+
<p style="font-size: 0.9em; color: #bbbbbb;">
|
174 |
+
Nota: El análisis se basa en heurísticas y puede requerir una revisión adicional para fines forenses.
|
175 |
+
</p>
|
176 |
</div>
|
177 |
"""
|
178 |
|
|
|
195 |
gr.Markdown("### Ejemplos de TXIDs válidos:")
|
196 |
gr.Examples(
|
197 |
examples=[
|
198 |
+
["a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d"],
|
199 |
["a83926f2fba1e446c0d5731a6866e78730fc3e21e31207fc0a3ee56e752843e9"]
|
200 |
],
|
201 |
inputs=tx_input
|