Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Fiabilidad y consistencia14 min de lectura

Detección de reorgs de bloques en Ethereum: profundidad RPC y confirmación segura

Detecta reorgs de bloques en Ethereum desde un único endpoint RPC, mide la profundidad mediante el enlace de hashes padre y elige una política de confirmación a partir de los puntos de bifurcación observados.

TL;DR

Los reorgs de bloques en Ethereum ocurren cuando la cadena que sigue un nodo cambia a una rama diferente, invalidando bloques previamente canónicos. Detectarlos desde un único endpoint RPC requiere basarse en los hashes de bloque y verificar el enlace de hashes padre, sin confiar en los números de bloque como identidades. La especificación JSON-RPC de Ethereum define eth_getBlockByNumber y eth_getBlockByHash, que devuelven un objeto de bloque con un campo parentHash que lo enlaza con su predecesor. Un detector acotado mantiene una ventana móvil de filas recientes (altura, hash, parentHash), vuelve a leer la cabeza en cada sondeo y retrocede hasta que el hash almacenado coincide con el parentHash observado, informando el número de bloques reemplazados como profundidad del reorg. Las etiquetas safe y finalized ofrecen garantías más sólidas, pero son juicios de la capa de consenso, no promesas absolutas. Cualquier recuento de reorgs observado es una muestra de la vista de ese endpoint, no la tasa real de reorgs de la red.

El mecanismo del reorg y por qué los números de bloque no son identidades

Una reorganización de blockchain, o reorg, ocurre cuando un nodo cambia de una rama de la cadena a otra que tiene más trabajo acumulado o, en el Ethereum de prueba de participación, mayor peso de atestaciones. Los bloques que eran canónicos bajo la rama antigua pasan a ser no canónicos, y cualquier estado derivado de ellos puede ser inválido. La especificación JSON-RPC de Ethereum describe los bloques como objetos con un campo parentHash que enlaza criptográficamente cada bloque con su predecesor, formando una cadena. Un número de bloque es simplemente una etiqueta para una posición en esa cadena, no una identidad única. Dos bloques diferentes pueden ocupar la misma altura en ramas competidoras.

Debido a que los números de bloque son etiquetas posicionales, un detector que solo almacena el último número de bloque y asume que el bloque en esa altura es estable pasará por alto los reorgs por completo. El enfoque correcto es tratar el hash del bloque como la identidad y verificar que el hash siga siendo alcanzable desde la cabeza actual recorriendo los enlaces de hashes padre. Este es el principio central detrás de una detección fiable de reorgs y es independiente de cualquier proveedor RPC específico. Para una introducción más amplia a los métodos RPC de Ethereum, consulta la guía de endpoints RPC (RPC Assistant).

  • Un bloque es canónico solo mientras la cadena que sigue el nodo lo contenga.
  • Los números de bloque son posiciones, no identidades; los hashes son identidades.
  • El enlace de hash padre es la señal principal para detectar un cambio de cadena.
  • El estado derivado por debajo del punto de bifurcación se vuelve inválido tras un reorg.

El enlace de hash padre como señal principal de detección

La especificación JSON-RPC de Ethereum establece que eth_getBlockByNumber devuelve un objeto de bloque para una altura dada, y eth_getBlockByHash devuelve un objeto de bloque para un hash dado, o null si el bloque es desconocido para el nodo. Ambos objetos incluyen un campo parentHash. Para detectar un reorg, vuelve a solicitar el hash almacenado para la altura N y compáralo con el parentHash del bloque que ahora está en la altura N+1. Si el hash almacenado para N ya no aparece como el padre de N+1, la cadena ha cambiado. Esta comparación es la señal fundamental de reorg.

Un punto sutil pero crítico: eth_getBlockByHash devuelve el bloque si el nodo todavía lo tiene, sea o no canónico. Un hash que se resuelve no es necesariamente un hash que sea canónico. La prueba de canonicalidad siempre requiere retroceder desde la cabeza. Esta distinción está documentada en la especificación JSON-RPC de Ethereum para eth_getBlockByHash y es esencial para una lógica de detector correcta.

  • Compara el hash almacenado en la altura N con el parentHash del bloque en N+1.
  • Un hash resoluble no es prueba de canonicalidad.
  • La canonicalidad se establece solo retrocediendo desde la cabeza.
  • Tanto eth_getBlockByNumber como eth_getBlockByHash devuelven null para bloques desconocidos.

Etiquetas safe y finalized: garantías documentadas y sus límites

La especificación JSON-RPC de Ethereum define etiquetas de bloque que incluyen latest, safe, finalized y pending. La etiqueta finalized es la garantía más fuerte que un nodo puede ofrecer y es el ancla adecuada para la liquidación irreversible. La etiqueta safe es un intermedio más débil que aún puede estar sujeto a reorgs bajo ciertas condiciones de red. Ambas son juicios de la capa de consenso que un nodo expone según su vista de la cadena, no promesas absolutas de que nunca pueda ocurrir un reorg a esa profundidad.

Depender únicamente de finalized para todas las operaciones puede ser poco práctico para aplicaciones de alta frecuencia porque la finalidad tarda tiempo. Muchos sistemas usan una política de profundidad de confirmación basada en estadísticas de reorgs observadas en lugar de esperar la finalidad. La disyuntiva está entre la velocidad de liquidación y la seguridad. Para un análisis detallado de cómo interactúa la finalidad con los reorgs, consulta la especificación JSON-RPC de Ethereum para eth_getBlockByNumber.

  • finalized es la etiqueta más fuerte, pero sigue siendo un juicio de la capa de consenso.
  • safe es más débil y puede sufrir reorgs bajo algunas condiciones.
  • Las políticas de profundidad de confirmación equilibran velocidad y seguridad.
  • El comportamiento del proveedor para estas etiquetas está documentado, pero varía según el proveedor.

Construir un detector de reorgs acotado con una ventana móvil

Un detector de reorgs práctico mantiene una ventana móvil de filas recientes (altura, hash, parentHash). En cada sondeo, vuelve a leer el bloque cabeza y retrocede por la ventana almacenada, comparando el hash almacenado en cada altura con el parentHash del bloque en la siguiente altura. El recorrido se detiene cuando el hash almacenado coincide con el parentHash observado. El número de bloques reemplazados es la profundidad del reorg, y la altura donde se detuvo el recorrido es el punto de bifurcación.

Este enfoque acotado evita el crecimiento ilimitado de memoria y mantiene el detector receptivo. El tamaño de la ventana debe ser al menos tan profundo como la política de confirmación que pretendes aplicar. Para una perspectiva complementaria sobre la conciliación de bloques y transacciones, consulta Conciliación de indexador EVM bloque por bloque.

  • Mantén una ventana móvil de filas (altura, hash, parentHash).
  • Vuelve a leer la cabeza en cada sondeo y retrocede hasta que los hashes coincidan.
  • Profundidad del reorg = número de bloques reemplazados; punto de bifurcación = altura donde se detuvo el recorrido.
  • El tamaño de la ventana debe superar tu profundidad de confirmación prevista.

Detector Node.js ejecutable con salida por sondeo

El siguiente script de Node.js se conecta a un único endpoint JSON-RPC de Ethereum, sondea el bloque cabeza y detecta reorgs mediante el enlace de hashes padre. Emite una salida por sondeo que incluye el número de cabeza, el hash de cabeza, la profundidad observada, la altura del punto de bifurcación y los bloques reemplazados. También mantiene un registro acumulativo para que puedas acumular tus propias estadísticas de reorgs medidas. Reemplaza RPC_URL con tu endpoint de la página de la red Ethereum de OnFinality.

El script usa eth_getBlockByNumber con la etiqueta latest para obtener la cabeza, y eth_getBlockByHash para recuperar bloques por hash al retroceder. Almacena una ventana móvil de los últimos WINDOW_SIZE bloques. En cada sondeo, compara el hash almacenado en cada altura con el parentHash del bloque en la siguiente altura. Si encuentra una discrepancia, informa la profundidad del reorg y el punto de bifurcación.

const { ethers } = require('ethers');

const RPC_URL = 'https://your-endpoint.onfinality.io'; // replace with your endpoint
const WINDOW_SIZE = 64; // number of recent blocks to track
const POLL_INTERVAL_MS = 12000; // ~1 block time

const provider = new ethers.JsonRpcProvider(RPC_URL);

// Rolling window: array of { height, hash, parentHash }
let window = [];
let cumulativeReorgs = [];

async function fetchBlockByNumber(height) {
  const block = await provider.send('eth_getBlockByNumber', [
    '0x' + height.toString(16),
    false
  ]);
  if (!block) return null;
  return {
    height: parseInt(block.number, 16),
    hash: block.hash,
    parentHash: block.parentHash
  };
}

async function fetchBlockByHash(hash) {
  const block = await provider.send('eth_getBlockByHash', [hash, false]);
  if (!block) return null;
  return {
    height: parseInt(block.number, 16),
    hash: block.hash,
    parentHash: block.parentHash
  };
}

async function poll() {
  const head = await fetchBlockByNumber('latest');
  if (!head) {
    console.log('Failed to fetch head block');
    return;
  }

  // Add head to window if new
  if (window.length === 0 || window[window.length - 1].height < head.height) {
    window.push(head);
    if (window.length > WINDOW_SIZE) window.shift();
  }

  // Walk backward to find fork point
  let forkPoint = null;
  let blocksReplaced = 0;

  for (let i = window.length - 1; i > 0; i--) {
    const stored = window[i - 1];
    const current = window[i];
    if (stored.hash !== current.parentHash) {
      // Mismatch: reorg detected
      forkPoint = stored.height;
      blocksReplaced = window.length - i;
      break;
    }
  }

  if (forkPoint !== null) {
    console.log(`REORG DETECTED: head=${head.height} hash=${head.hash}`);
    console.log(`  fork point height: ${forkPoint}`);
    console.log(`  blocks replaced: ${blocksReplaced}`);
    cumulativeReorgs.push({ timestamp: Date.now(), forkPoint, blocksReplaced });
    // Rewind window to fork point
    window = window.filter(b => b.height <= forkPoint);
  } else {
    console.log(`No reorg. head=${head.height} hash=${head.hash}`);
  }

  console.log(`Cumulative reorgs observed: ${cumulativeReorgs.length}`);
}

setInterval(poll, POLL_INTERVAL_MS);
poll();

Medir la profundidad de reorg y la distribución de puntos de bifurcación

Ejecutar el detector durante un periodo de observación prolongado produce una distribución de puntos de bifurcación y profundidades de reorg. Esta distribución es la base empírica para elegir una profundidad de confirmación. Una ventana de observación corta solo produce una muestra de la vista de ese endpoint, no una estimación de la tasa real de reorgs de la red. Para hacer afirmaciones sobre la frecuencia de reorgs a nivel de red, necesitas un periodo de observación largo y, idealmente, múltiples endpoints independientes.

Usa la siguiente plantilla de tabla de resultados para registrar tus propias mediciones. Rellénala con datos de tu detector. No te bases en cifras citadas de publicaciones de blog; mide contra tu propio endpoint. Para un método que compare endpoints, consulta Consistencia multi-endpoint RPC y retraso de cabeza.

  • Columnas de la tabla de resultados: periodo de observación, endpoint, sondeos totales, reorgs observados, profundidad máxima, profundidad mediana, alturas de puntos de bifurcación.
  • Registra la marca de tiempo y la altura de bloque de cada evento de reorg.
  • Compara distribuciones entre múltiples endpoints si es posible.
  • Una distribución completa requiere un periodo de observación largo, no una muestra corta.

Elegir una profundidad de confirmación a partir de los datos observados

La política de profundidad de confirmación debe derivarse de la distribución observada de puntos de bifurcación, no copiarse de una publicación de blog. Si tu detector observa que el 99% de los reorgs tienen una profundidad de 2 bloques o menos durante un periodo largo, una profundidad de 12 bloques proporciona un margen amplio. Sin embargo, la elección también depende del valor en riesgo y del coste de retrasar la liquidación. Una política de confirmación más profunda ralentiza la liquidación, pero reduce la probabilidad de actuar sobre un bloque reorganizado.

Para la liquidación irreversible, la etiqueta finalized es el ancla más fuerte. Para operaciones de alta frecuencia, una política basada en profundidad puede ser más práctica. La clave es basar la decisión en tus propias mediciones y documentar los supuestos. Para un análisis relacionado sobre la detección de retraso, consulta Detectar un nodo RPC por detrás de la punta de la cadena.

  • Deriva la profundidad de confirmación de la distribución observada de puntos de bifurcación.
  • Considera las disyuntivas entre valor en riesgo y velocidad de liquidación.
  • Usa finalized para liquidación irreversible cuando sea posible.
  • Documenta los supuestos y reevalúa periódicamente.

Remediación del indexador: rebobinar y reindexar tras un reorg

Para los indexadores, un reorg invalida el estado derivado por debajo del punto de bifurcación. Un detector que solo registra reorgs es insuficiente; la ruta de remediación debe diseñarse antes de que se active. El enfoque estándar es rebobinar el indexador hasta el punto de bifurcación y reindexar hacia adelante desde allí. Esto requiere que el indexador pueda identificar el punto de bifurcación y que tenga una forma de revertir el estado derivado, como transacciones de base de datos o registros versionados.

La ruta de remediación debe probarse con regularidad. Si el indexador no puede rebobinar, puede servir datos obsoletos o incorrectos tras un reorg. Para un tratamiento detallado de la conciliación, consulta Conciliación de indexador EVM bloque por bloque. Los métodos de recuperación masiva como eth_getBlockReceipts: recibos en bloque en una sola llamada pueden acelerar la reindexación.

  • Un reorg invalida el estado derivado por debajo del punto de bifurcación.
  • Remediación: rebobinar hasta el punto de bifurcación, reindexar hacia adelante.
  • Diseña y prueba la ruta de remediación antes de necesitarla.
  • Usa métodos de recuperación masiva para acelerar la reindexación.

Limitaciones, disyuntivas y variabilidad entre proveedores

Ningún endpoint RPC único proporciona una vista completa de la red. Cualquier recuento de reorgs observado es una muestra de la vista de ese endpoint y puede no reflejar la tasa real de reorgs de la red. El comportamiento específico del proveedor para las etiquetas de bloque, el almacenamiento en caché y la propagación de la cabeza varía. La especificación JSON-RPC de Ethereum define la semántica del protocolo, pero los detalles de implementación están documentados por proveedor y pueden variar.

Una política de confirmación más profunda aumenta la seguridad, pero ralentiza la liquidación. Una política más superficial acelera la liquidación, pero aumenta el riesgo de reorg. La profundidad óptima depende de la tolerancia al riesgo de la aplicación y de la distribución observada de reorgs. No existe un número seguro universal. Además, el propio detector añade carga al endpoint; la frecuencia de sondeo y el tamaño de la ventana deben ajustarse para equilibrar la latencia de detección con el uso de recursos. Para consideraciones de precios, consulta Precios de RPC.

  • Las observaciones de un solo endpoint son muestras, no verdades de toda la red.
  • El comportamiento del proveedor para etiquetas y caché varía; consulta la documentación.
  • Una confirmación más profunda ralentiza la liquidación; una más superficial aumenta el riesgo.
  • El sondeo del detector añade carga; ajusta la frecuencia y el tamaño de la ventana.

Solución de problemas comunes del detector

Si el detector no informa reorgs pero sospechas que ocurrió uno, verifica que el tamaño de la ventana sea lo suficientemente grande para cubrir la profundidad del reorg. Un reorg más profundo que la ventana no se detectará porque los hashes almacenados ya se habrán desplazado fuera. Comprueba también que el endpoint no esté almacenando respuestas en caché; algunos proveedores cachean eth_getBlockByNumber durante un breve periodo, lo que puede enmascarar reorgs. Usa eth_getBlockByHash para la recuperación direccionada por hash y evitar la ambigüedad de la caché.

Si el detector informa frecuentes falsos positivos, asegúrate de estar comparando los campos correctos. El parentHash del bloque en la altura N+1 debe coincidir con el hash del bloque en la altura N. Una discrepancia en la numeración de alturas o una condición de carrera entre sondeos puede causar resultados espurios. Verifica también que el endpoint esté completamente sincronizado; un nodo retrasado puede servir bloques obsoletos. Para obtener ayuda con la selección de endpoints, consulta el servicio de API y el hub de aprendizaje de OnFinality.

  • Ventana demasiado pequeña: se pasan por alto reorgs profundos.
  • La caché del proveedor puede enmascarar reorgs; usa eth_getBlockByHash.
  • Falsos positivos: revisa las comparaciones de campos y la numeración de alturas.
  • Nodo retrasado: verifica el estado de sincronización antes de confiar en los resultados.

Próximos pasos: poner en producción la detección de reorgs

Para poner en producción la detección de reorgs, integra el detector en tu stack de monitorización y alerta sobre eventos de reorg. Registra cada reorg con marca de tiempo, punto de bifurcación y profundidad en un almacén persistente. Con el tiempo, estos datos informan tu política de profundidad de confirmación. Considera ejecutar detectores contra múltiples endpoints para comparar vistas y detectar anomalías específicas del proveedor.

Para sistemas en producción, combina la detección de reorgs con una ruta de remediación robusta. Prueba el procedimiento de rebobinado y reindexación con regularidad. Usa la etiqueta finalized para liquidación irreversible cuando sea posible. Para opciones de endpoint, explora la página de la red Ethereum de OnFinality y revisa Precios de RPC para elegir un plan que se ajuste a tu frecuencia de sondeo. La guía de endpoints RPC (RPC Assistant) proporciona contexto adicional sobre la selección de endpoints.

  • Integra el detector en la monitorización y alerta sobre reorgs.
  • Persiste los eventos de reorg para el análisis de distribución a largo plazo.
  • Ejecuta detectores contra múltiples endpoints para comparar.
  • Prueba los procedimientos de remediación con regularidad.

Nunca te preocupes por la infraestructura nuevamente

OnFinality elimina la carga pesada de DevOps para que puedas construir de forma más inteligente y rápida.

Comenzar