Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Rendimiento y optimización13 min de lectura

Tiempos de bloque de Base y Flashblocks: medir preconfirmaciones sobre RPC

Un manual reproducible de medición RPC para los bloques L2 de 2 segundos de Base, el flujo de preconfirmación Flashblocks de ~250 ms y las tres superficies de latencia que realmente atraviesa una transacción.

TL;DR

Base produce bloques L2 con una cadencia fija (documentada como un tiempo de bloque de 2 segundos, un parámetro de cadena que varía según la cadena y la actualización), mientras que el flujo de preconfirmación Flashblocks emite actualizaciones sub-segundo (documentadas en aproximadamente 250 ms) antes del bloque L2 canónico. Una preconfirmación es una promesa de inclusión del secuenciador, no una garantía de consenso: es más débil que un bloque L2 y mucho más débil que la finalidad de L1. Para medir el tiempo de bloque efectivo debes sondear eth_blockNumber a intervalos cortos, obtener cada altura con eth_getBlockByNumber y diferenciar el campo timestamp en lugar de confiar en suposiciones de reloj de pared. Para medir la latencia de confirmación debes separar tres superficies: inclusión en flashblock/pendiente, eth_getTransactionReceipt no nulo y etiquetas safe/finalized. Este artículo ofrece un arnés Node.js ejecutable, una tabla de resultados para completar por endpoint y las limitaciones honestas de las lecturas basadas en preconfirmaciones.

Producción de bloques de Base y el modelo del secuenciador

Base es un rollup de OP Stack. La especificación del nodo de rollup de OP Stack describe un secuenciador que ordena transacciones, construye bloques L2 y los publica, con el nodo de rollup derivando el estado de la cadena a partir de los datos de L1. Esa arquitectura es la razón por la que el tiempo de bloque L2 y la finalidad de L1 son relojes separados: el secuenciador puede producir bloques L2 de forma continua mientras la confirmación en L1 de los datos subyacentes va por detrás.

El tiempo de bloque L2 es un parámetro de cadena, no una constante universal. Base documenta un tiempo de bloque L2 de 2 segundos, y lo mejor es tratarlo como 'documentado / varía según la cadena y la actualización' porque las constantes de tiempo de bloque son parámetros de gobernanza y actualización que pueden cambiar. Si te integras con Base, verifica el valor actual contra la propia cadena en lugar de codificarlo de forma fija. La página de red de Base es el punto de entrada para los detalles a nivel de cadena, y la guía del endpoint RPC de Base cubre la configuración del endpoint.

Debido a que el secuenciador está actualmente centralizado, el ordenamiento es una declaración de confianza sobre ese operador en lugar de una garantía de consenso. Esto importa para cualquier aplicación que trate una preconfirmación rápida como si estuviera liquidada.

  • La cadencia de producción de bloques L2 es un parámetro de cadena (documentado como 2 segundos en Base; varía según la cadena y la actualización).
  • El secuenciador ordena y construye bloques L2; L1 proporciona disponibilidad de datos y finalidad eventual.
  • La secuenciación centralizada significa que las preconfirmaciones son promesas del operador, no resultados de consenso.

Qué prometen realmente las preconfirmaciones de Flashblocks

Flashblocks es un mecanismo de preconfirmación que emite actualizaciones sub-segundo antes del bloque L2 canónico. La documentación de Base describe Flashblocks como emisor de preconfirmaciones de aproximadamente 250 ms, lo que brinda a las aplicaciones una lectura más rápida del estado pendiente que esperar al siguiente bloque L2 de 2 segundos. La descripción autorizada está en Documentación de Base: descripción general de Flashblocks.

Una preconfirmación es una promesa del secuenciador de que una transacción será incluida. Es más débil que un bloque L2 que ya ha sido producido, y mucho más débil que la finalidad de L1. Una aplicación que trata un flashblock como final queda expuesta a reorganizaciones del secuenciador: el secuenciador puede reordenar o descartar transacciones antes de que lleguen a un bloque L2 canónico, y las reorganizaciones de L1 aún pueden afectar la cadena derivada.

La consecuencia práctica es que Flashblocks cambia lo que un trader de baja latencia puede observar (lecturas más rápidas, visibilidad más temprana del estado pendiente) sin cambiar la semántica de finalidad. La medición que importa para la corrección, es decir, cuánto tiempo hasta que una transacción es segura o finalizada, no cambia por la presencia de un flujo de preconfirmación.

  • Flashblocks: documentado en actualizaciones de preconfirmación de aproximadamente 250 ms antes del bloque L2.
  • Fortaleza de la preconfirmación: más débil que un bloque L2, mucho más débil que la finalidad de L1.
  • La disponibilidad y el momento exacto son 'documentado / varía según el proveedor y la actualización'.

Las tres superficies de latencia que atraviesa una transacción

Una transacción en Base experimenta al menos tres superficies de latencia distintas, y confundirlas es el error de medición más común. La superficie uno es la inclusión en el flujo pendiente o de flashblocks del secuenciador. La superficie dos es la aparición en un bloque L2, observable cuando eth_getTransactionReceipt devuelve un valor no nulo. La superficie tres es la progresión a las etiquetas de bloque safe y finalized y, en última instancia, a L1.

Un indexador que necesita durabilidad debe basarse en safe o finalized, no en la presencia del recibo. La presencia del recibo solo prueba que el secuenciador incluyó la transacción en un bloque L2; no prueba que el bloque sobrevivirá a una reorganización. La semántica de las etiquetas se cubre en detalle en Finalidad de Base OP Stack, bloques safe y finalized, y el lado L1 del reloj se cubre en Derivación L1 y timestamp de Base OP Stack.

Para la lógica crítica para la corrección, define tu umbral de aceptación explícitamente: qué superficie cuenta como 'hecho' para tu caso de uso. Una interfaz de trading puede aceptar la superficie uno; un sistema de liquidación debería requerir la superficie tres.

  • Superficie 1: inclusión pendiente/flashblock (la más rápida, la más débil).
  • Superficie 2: eth_getTransactionReceipt no nulo (inclusión en bloque L2).
  • Superficie 3: etiquetas safe/finalized y finalidad de L1 (la más lenta, la más fuerte).

Medir la cadencia de bloques L2 con sondeo de eth_blockNumber

La forma reproducible de medir el tiempo de bloque observado de Base es sondear eth_blockNumber a intervalos cortos, luego obtener cada nueva altura con eth_getBlockByNumber y diferenciar el campo timestamp. No confíes en suposiciones de reloj de pared sobre cuándo 'deberían' llegar los bloques; el campo timestamp es el propio registro de la cadena, y la distribución observada del intervalo entre bloques es lo que tu aplicación experimenta realmente.

Sondea más rápido que el tiempo de bloque esperado para no perder alturas. Si la cadencia documentada es de 2 segundos, un intervalo de sondeo de 250 ms da aproximadamente ocho muestras por bloque y es un punto de partida razonable. Registra cada altura que observes, luego calcula las diferencias entre timestamps consecutivos.

La especificación JSON-RPC 2.0 define el sobre de solicitud/respuesta y la semántica del objeto de error utilizados por estas llamadas; la especificación JSON-RPC de Ethereum define eth_blockNumber y eth_getBlockByNumber. Trátalas como las fuentes primarias autorizadas para la semántica del protocolo, y trata el comportamiento específico del proveedor (caché, balanceo de carga, límites de tasa) como 'documentado / varía según el proveedor'.

  • Sondea eth_blockNumber más rápido que el tiempo de bloque esperado para evitar perder alturas.
  • Usa las diferencias de timestamp de eth_getBlockByNumber, no el reloj de pared local, para la cadencia.
  • La semántica del protocolo proviene de las especificaciones JSON-RPC 2.0 y JSON-RPC de Ethereum.

Arnés Node.js ejecutable para el muestreo de intervalos de bloque

El script a continuación muestrea eth_blockNumber durante una ventana fija, obtiene el timestamp de cada nuevo bloque mediante eth_getBlockByNumber e imprime la mediana y el intervalo máximo entre bloques. Solo utiliza el fetch integrado disponible en Node.js moderno, por lo que no hay dependencias que instalar. Establece RPC_URL en tu endpoint antes de ejecutarlo.

Ejecútalo durante varios minutos para obtener una muestra significativa. Las ventanas cortas producen medianas ruidosas, y un solo sondeo perdido puede crear un hueco artificial, así que registra las alturas sin procesar junto con las diferencias cuando estés diagnosticando irregularidades.

// block-interval.js — measure observed L2 block cadence over RPC
// Usage: RPC_URL=https://your-base-endpoint node block-interval.js

const RPC_URL = process.env.RPC_URL;
if (!RPC_URL) throw new Error('Set RPC_URL');

const POLL_MS = 250;        // poll faster than the expected block time
const WINDOW_MS = 120000;   // sample window: 2 minutes

let id = 0;
async function rpc(method, params = []) {
  const body = { jsonrpc: '2.0', id: ++id, method, params };
  const res = await fetch(RPC_URL, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });
  const json = await res.json();
  if (json.error) throw new Error(`${method}: ${JSON.stringify(json.error)}`);
  return json.result;
}

const seen = new Map(); // height -> timestamp (hex)
const start = Date.now();

async function sample() {
  const hexHeight = await rpc('eth_blockNumber');
  const height = Number(BigInt(hexHeight));
  if (!seen.has(height)) {
    const block = await rpc('eth_getBlockByNumber', [hexHeight, false]);
    if (block && block.timestamp) seen.set(height, block.timestamp);
  }
}

(async () => {
  while (Date.now() - start < WINDOW_MS) {
    try { await sample(); } catch (e) { console.error('sample error:', e.message); }
    await new Promise((r) => setTimeout(r, POLL_MS));
  }

  const heights = [...seen.keys()].sort((a, b) => a - b);
  const deltas = [];
  for (let i = 1; i < heights.length; i++) {
    const prev = Number(BigInt(seen.get(heights[i - 1])));
    const cur = Number(BigInt(seen.get(heights[i])));
    deltas.push(cur - prev);
  }
  deltas.sort((a, b) => a - b);
  const median = deltas.length ? deltas[Math.floor(deltas.length / 2)] : null;
  const max = deltas.length ? deltas[deltas.length - 1] : null;
  console.log(JSON.stringify({
    blocksObserved: heights.length,
    firstHeight: heights[0],
    lastHeight: heights[heights.length - 1],
    medianIntervalSeconds: median,
    maxIntervalSeconds: max,
  }, null, 2));
})();

Medir la latencia del recibo de una transacción enviada

La cadencia de bloques es una propiedad de la cadena; la latencia del recibo es lo que experimenta una transacción específica. El segundo arnés envía una transacción (o acepta un hash conocido) y sondea eth_getTransactionReceipt hasta que devuelve un valor no nulo, registrando el tiempo transcurrido. Esto aísla la superficie dos de la superficie uno, porque la presencia del recibo requiere la inclusión en un bloque L2.

Si estás midiendo la superficie uno, necesitas un proveedor que exponga el flujo de preconfirmación; esa disponibilidad es 'documentado / varía según el proveedor y la actualización'. El arnés de recibos a continuación funciona con cualquier endpoint estándar y es la línea base que debes registrar antes de añadir instrumentación específica de preconfirmación.

// receipt-latency.js — time eth_getTransactionReceipt until non-null
// Usage: RPC_URL=... TX_HASH=0x... node receipt-latency.js

const RPC_URL = process.env.RPC_URL;
const TX_HASH = process.env.TX_HASH;
if (!RPC_URL || !TX_HASH) throw new Error('Set RPC_URL and TX_HASH');

const POLL_MS = 200;
const TIMEOUT_MS = 60000;

let id = 0;
async function rpc(method, params = []) {
  const body = { jsonrpc: '2.0', id: ++id, method, params };
  const res = await fetch(RPC_URL, {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });
  const json = await res.json();
  if (json.error) throw new Error(`${method}: ${JSON.stringify(json.error)}`);
  return json.result;
}

(async () => {
  const t0 = Date.now();
  while (Date.now() - t0 < TIMEOUT_MS) {
    const receipt = await rpc('eth_getTransactionReceipt', [TX_HASH]);
    if (receipt) {
      const block = await rpc('eth_getBlockByNumber', [receipt.blockNumber, false]);
      console.log(JSON.stringify({
        receiptLatencyMs: Date.now() - t0,
        blockNumber: receipt.blockNumber,
        blockTimestamp: block ? block.timestamp : null,
        status: receipt.status,
      }, null, 2));
      return;
    }
    await new Promise((r) => setTimeout(r, POLL_MS));
  }
  console.error('timeout: receipt not observed within window');
})();

Tabla de resultados para completar por endpoint y región

Los números diferirán entre endpoints y regiones debido a la ruta de red, la versión del nodo, el balanceo de carga y la caché. En lugar de citar una única cifra, registra tus propias mediciones en una tabla como la siguiente. Ejecuta cada arnés contra cada endpoint desde la misma máquina cliente y región, a la misma hora del día, y repite al menos tres veces.

La columna de retardo safe/finalized requiere una tercera medición: sondear eth_getBlockByNumber con las etiquetas 'safe' y 'finalized' y comparar sus alturas con 'latest'. Ese retardo es el costo de durabilidad de esperar la finalidad, y es el número que un indexador debería presupuestar.

  • URL del endpoint y región del cliente que realiza la medición.
  • Intervalo mediano observado entre bloques (segundos) e intervalo máximo (segundos).
  • Latencia del recibo (ms) desde el envío hasta eth_getTransactionReceipt no nulo.
  • Retardo de la etiqueta safe (bloques por detrás de latest) y retardo de la etiqueta finalized (bloques por detrás de latest).
  • Notas: proveedor, versión del nodo si está expuesta y cualquier irregularidad observada.

Por qué los endpoints y las regiones producen números diferentes

Un endpoint RPC detrás de un balanceador de carga puede servir lecturas desde un nodo ligeramente por detrás de la punta, por lo que los intervalos sondeados parecen irregulares incluso cuando la cadena produce bloques según lo previsto. Esto es un artefacto de medición, no una anomalía de la cadena. Si ves un hueco seguido de una ráfaga, puede que estés rotando entre nodos con diferentes alturas de punta.

La distancia geográfica añade latencia de ida y vuelta a cada sondeo, lo que infla la latencia del recibo sin cambiar la cadencia de bloques. Las políticas de caché del proveedor también pueden afectar la rapidez con la que un bloque recién producido se vuelve visible a través de un endpoint determinado. Trata todo esto como 'documentado / varía según el proveedor' y contrólalo fijando un único endpoint por ejecución de medición.

Para el monitoreo en producción, rastrea estas señales de forma continua en lugar de una sola vez. Monitoreo de endpoints RPC cubre el lado operativo, y Estado de sincronización del nodo Base OP Stack y la Engine API explica cómo saber si un nodo está retrasado.

  • Los endpoints con balanceo de carga pueden servir lecturas desde un nodo por detrás de la punta.
  • La distancia geográfica infla la latencia del recibo pero no la cadencia de bloques.
  • Fija un endpoint por ejecución de medición para mantener los resultados comparables.

Solución de problemas de intervalos irregulares y recibos faltantes

Si tu distribución de intervalos de bloque muestra huecos grandes, primero verifica si estás perdiendo sondeos debido a límites de tasa. Un 429 o una conexión caída producen un hueco artificial. Registra las alturas sin procesar y el estado HTTP de cada sondeo para poder distinguir una pausa de la cadena de un fallo del lado del cliente.

Si eth_getTransactionReceipt nunca devuelve un valor no nulo, verifica el hash de la transacción y que estás consultando la misma cadena. Un recibo que aparece en un endpoint pero no en otro suele indicar que el segundo endpoint está por detrás de la punta. Si el recibo aparece pero el timestamp del bloque está lejos de tu hora de envío, es posible que estés observando una reorganización en la que la transacción se re-incluyó en un bloque diferente.

Si las etiquetas safe o finalized no avanzan, el problema suele estar del lado de L1 en lugar del lado de L2. Verifica la ruta de derivación descrita en Derivación L1 y timestamp de Base OP Stack antes de asumir un problema de L2.

  • Los límites de tasa y las conexiones caídas crean huecos artificiales.
  • Un recibo visible en un endpoint pero no en otro sugiere un nodo retrasado.
  • Las etiquetas safe/finalized estancadas suelen indicar una condición del lado de L1.

Limitaciones, suposiciones de confianza y compensaciones

Flashblocks y cualquier endpoint de preconfirmación son características del proveedor y de la cadena cuya disponibilidad y momento exacto son 'documentado / varía según el proveedor y la actualización'. No construyas lógica de corrección que asuma que un flujo de preconfirmación siempre está presente o siempre llega a un intervalo fijo.

El secuenciador está actualmente centralizado, por lo que 'preconfirmado' es una declaración de confianza sobre el secuenciador en lugar de una garantía de consenso. Las preconfirmaciones reducen la latencia pero no reducen las suposiciones de confianza. Las aplicaciones que requieren durabilidad aún deben esperar las etiquetas safe o finalized, aceptando la latencia adicional que impone la finalidad.

Las constantes de tiempo de bloque son parámetros de gobernanza y actualización que pueden cambiar. Cualquier suposición codificada de forma fija sobre una cadencia de 2 segundos o un intervalo de preconfirmación de 250 ms debe tratarse como un valor de configuración que vuelves a verificar, no como una constante incrustada en tu código.

  • Disponibilidad y momento de la preconfirmación: 'documentado / varía según el proveedor y la actualización'.
  • La secuenciación centralizada convierte las preconfirmaciones en una declaración de confianza, no en consenso.
  • Las constantes de tiempo de bloque pueden cambiar mediante gobernanza y actualizaciones.

Próximos pasos para la medición en producción

Comienza ejecutando el arnés de intervalos de bloque contra tu endpoint principal durante al menos diez minutos y completando la tabla de resultados. Luego ejecuta el arnés de latencia de recibos para una transacción representativa y añade la medición del retardo safe/finalized. Juntos, estos tres números describen el presupuesto de latencia al que realmente se enfrenta tu aplicación.

Una vez que tengas una línea base, automatiza la medición de forma programada y alerta sobre regresiones. El centro de aprendizaje de OnFinality recopila análisis relacionados, y si necesitas endpoints contra los que medir, revisa Precios de RPC y el Servicio de API antes de escalar tu muestreo entre regiones.

Por último, documenta tu umbral de aceptación explícitamente en tu base de código: qué superficie cuenta como confirmada para cada operación. Esa única decisión determina si Flashblocks te ayuda o te expone silenciosamente al riesgo de reorganización.

  • Línea base: intervalo de bloque, latencia de recibo, retardo safe/finalized por endpoint.
  • Automatiza la medición y alerta sobre regresiones.
  • Documenta qué superficie de latencia cuenta como confirmada para cada operación.

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