From 46636bdba9f4f2e1e9e92bd777a1ef6512b04905 Mon Sep 17 00:00:00 2001 From: Aitor Date: Thu, 4 Jun 2026 10:37:25 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20check=20OP=5FRETURN=20en=20motor=20de=20?= =?UTF-8?q?an=C3=A1lisis,=20banda=20BAJA=20forzada?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dashboard.html | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/dashboard.html b/dashboard.html index f8075c8..ffa30b9 100644 --- a/dashboard.html +++ b/dashboard.html @@ -1024,7 +1024,7 @@ input_reuse: 25, input_type_mixing: 14, output_type_mismatch: 8, round_numbers: 10, rbf: 5, peeling: 8, unnecessary_input: 12, dust: 8, change_detection: 10, - wallet_fingerprint: 6, batch_payment: 45, entity_ofac: 20, + wallet_fingerprint: 6, batch_payment: 45, entity_ofac: 20, op_return: 30, }; let deductions = 0; @@ -1459,7 +1459,29 @@ }); if (isBatch) deductions += weights.batch_payment; - // ── 15. Timing analysis — informativo ──────────────────────────── + // ── 15. OP_RETURN ───────────────────────────────────────────────── + // Detecta outputs OP_RETURN (nulldata): presencia y tamaño total en bytes. + // No muestra el contenido — lo relevante para privacidad es que hay datos + // arbitrarios, no qué dicen. Ver v1.2.1 del changelog. + const opReturnOuts = tx.vout.filter(v => isOpReturn(v)); + const hasOpReturn = opReturnOuts.length > 0; + const opReturnBytes = opReturnOuts.reduce((s, v) => { + // scriptpubkey: "6a" + longitud (1 byte) + datos. Datos = (hex.length/2) - 2 + const hex = v.scriptpubkey || ""; + return s + Math.max(0, hex.length / 2 - 2); + }, 0); + checks.push({ + id:"op_return", label:"Datos OP_RETURN", certainty:"CERTEZA", pass:!hasOpReturn, + actionability: "no_corregible", + detail: hasOpReturn + ? `${opReturnOuts.length} output${opReturnOuts.length > 1 ? "s" : ""} OP_RETURN con ${opReturnBytes} bytes de datos arbitrarios. Revela que esta transacción usa un protocolo o servicio que escribe datos en la cadena (Stamps, Ordinals, OpenTimestamps, Omni, etc.). Se informa la presencia y el tamaño, no el contenido.` + : "No se detectan outputs OP_RETURN.", + didactic: "Un output OP_RETURN contiene datos arbitrarios que cualquiera puede leer. Su presencia revela el uso de un protocolo concreto y puede vincular esta transacción con actividad on-chain identificable. El contenido no se muestra — para la privacidad lo relevante es que existe, no qué dice.", + penalty: hasOpReturn ? weights.op_return : 0, + }); + if (hasOpReturn) deductions += weights.op_return; + + // ── 16. Timing analysis — informativo ──────────────────────────── let timingDetail = "No hay timestamp disponible (transacción pendiente o sin confirmar)."; if (tx.status?.block_time) { const date = new Date(tx.status.block_time * 1000); @@ -1547,7 +1569,9 @@ // ── Score compuesto ─────────────────────────────────────────────── const maxPossible = Object.values(weights).reduce((a,b)=>a+b,0); - const score = Math.max(0, Math.min(100, Math.round(100 - (deductions / maxPossible) * 100))); + const rawScore = Math.max(0, Math.min(100, Math.round(100 - (deductions / maxPossible) * 100))); + // OP_RETURN es incompatible con privacidad aceptable — fuerza banda BAJA como máximo. + const score = hasOpReturn ? Math.min(rawScore, 44) : rawScore; return { score, checks,