fix: check OP_RETURN en motor de análisis, banda BAJA forzada
This commit is contained in:
+27
-3
@@ -1024,7 +1024,7 @@
|
|||||||
input_reuse: 25, input_type_mixing: 14, output_type_mismatch: 8,
|
input_reuse: 25, input_type_mixing: 14, output_type_mismatch: 8,
|
||||||
round_numbers: 10, rbf: 5, peeling: 8,
|
round_numbers: 10, rbf: 5, peeling: 8,
|
||||||
unnecessary_input: 12, dust: 8, change_detection: 10,
|
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;
|
let deductions = 0;
|
||||||
|
|
||||||
@@ -1459,7 +1459,29 @@
|
|||||||
});
|
});
|
||||||
if (isBatch) deductions += weights.batch_payment;
|
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).";
|
let timingDetail = "No hay timestamp disponible (transacción pendiente o sin confirmar).";
|
||||||
if (tx.status?.block_time) {
|
if (tx.status?.block_time) {
|
||||||
const date = new Date(tx.status.block_time * 1000);
|
const date = new Date(tx.status.block_time * 1000);
|
||||||
@@ -1547,7 +1569,9 @@
|
|||||||
|
|
||||||
// ── Score compuesto ───────────────────────────────────────────────
|
// ── Score compuesto ───────────────────────────────────────────────
|
||||||
const maxPossible = Object.values(weights).reduce((a,b)=>a+b,0);
|
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 {
|
return {
|
||||||
score, checks,
|
score, checks,
|
||||||
|
|||||||
Reference in New Issue
Block a user