Logo
Nuevos usuarios de RPC: 35% de descuento el primer mesVer oferta
OnFinality Learn
Guías de red y protocolo12 min de lectura

Derivación L1 y marcas de tiempo de Base OP Stack vía RPC

Cómo la derivación de OP Stack vincula cada marca de tiempo de bloque L2 de Base a un origen L1, y cómo leer esa procedencia vía RPC.

TL;DR

En OP Stack, el pipeline de derivación lee lotes de L1 y transacciones de depósito para producir bloques L2, y cada cabecera de bloque L2 lleva un origen L1 (un número de bloque L1 y una marca de tiempo L1). Dado que las marcas de tiempo de L1 son la fuente de tiempo canónica, la marca de tiempo de un bloque L2 está acotada por la marca de tiempo de su origen L1, por lo que el tiempo L2 es un derivado del tiempo L1. Puedes leer esta procedencia vía RPC combinando la marca de tiempo estándar de L2 eth_getBlockByNumber con el namespace rollup de op-node, especialmente optimism_syncStatus, que expone las cabezas L2 unsafe, safe y finalized junto con sus orígenes L1. La indexación solo por marca de tiempo no es segura ante reorgs porque el mismo segundo de reloj de pared puede mapear a diferentes bloques L2 antes y después de una reorg; anclar a un origen L1 hace que el mapeo sea reproducible. Esta guía muestra el mecanismo, lectores Node.js ejecutables, una tabla de resultados para completar contra tu propio endpoint, y los límites de la procedencia unsafe versus safe versus finalized.

Producción de bloques L2 de Base y el pipeline de derivación

Base es un L2 de OP Stack. Un secuenciador ordena las transacciones de usuario y produce bloques L2 rápidamente; estos bloques son inicialmente unsafe porque aún no han sido derivados de datos publicados en L1. El pipeline de derivación de OP Stack luego lee datos de L1, incluidos envíos de lotes y transacciones de depósito, y reconstruye la cadena L2 canónica a partir de ellos. La Especificación de OP Stack - Derivación define este pipeline como la fuente autoritativa del estado de la cadena L2.

La consecuencia práctica es que la producción de bloques L2 y la finalidad de bloques L2 son cuestiones separadas. El secuenciador proporciona inclusión de baja latencia, mientras que la derivación contra L1 da a la cadena su historia canónica y re-derivable. Para un consumidor de RPC, eso significa que un bloque que lees como latest puede reorganizarse más tarde, mientras que un bloque que ha sido derivado y finalizado en L1 es estable.

La documentación de Base describe el motor de ejecución L2 y la superficie RPC del nodo en Documentación de Base - Motor de ejecución L2 / RPC del nodo. El motor de ejecución almacena bloques L2; el op-node (nodo rollup) impulsa la derivación y expone métodos RPC específicos de rollup que revelan la procedencia L1.

  • Secuenciador: ordena transacciones, emite bloques L2 unsafe.
  • Batcher: publica datos de transacciones L2 en L1 en lotes.
  • Pipeline de derivación: lee lotes y depósitos de L1, reconstruye bloques L2.
  • op-node: expone RPC de rollup como optimism_syncStatus y optimism_outputAtBlock.

Origen L1 como fuente de tiempo canónica para las marcas de tiempo L2

Cada cabecera de bloque L2 lleva un origen L1: el número de bloque L1 y la marca de tiempo L1 de los que se deriva el bloque L2. Las marcas de tiempo L1 son la fuente de tiempo canónica para las marcas de tiempo de bloques L2, por lo que la marca de tiempo de un bloque L2 está acotada por la marca de tiempo de su origen L1. En otras palabras, el tiempo L2 es un derivado del tiempo L1, no un reloj independiente.

Este diseño mantiene las marcas de tiempo L2 consistentes con la cadena L1 que en última instancia las asegura. Si indexas datos L2 solo por marca de tiempo, estás indexando por un valor que solo tiene sentido en relación con un origen L1. Dos bloques L2 con la misma marca de tiempo pueden existir en contextos de derivación diferentes, y una reorg puede cambiar qué bloque L2 ocupa una marca de tiempo dada.

El RPC de rollup de op-node expone esta relación. optimism_syncStatus devuelve las cabezas L2 unsafe, safe y finalized junto con sus orígenes L1, y optimism_outputAtBlock devuelve la raíz de salida y la referencia de bloque para un bloque L2 dado. Estos métodos te permiten adjuntar un número de bloque L1 a cualquier bloque L2 que leas.

  • La cabecera de bloque L2 incluye el origen L1 (número de bloque L1 y marca de tiempo L1).
  • La marca de tiempo L2 está acotada por la marca de tiempo del origen L1.
  • optimism_syncStatus expone las cabezas L2 unsafe/safe/finalized y sus orígenes L1.
  • optimism_outputAtBlock devuelve la raíz de salida y la referencia de bloque para un bloque L2.

Leer la procedencia de bloques L2 con RPC estándar y de rollup

El eth_getBlockByNumber estándar de L2 devuelve la marca de tiempo, el número, el hash y las transacciones del bloque L2. Eso por sí solo no te dice el origen L1. Para adjuntar procedencia, llama al namespace rollup de op-node. optimism_syncStatus te da las cabezas L2 unsafe, safe y finalized actuales y sus orígenes L1; optimism_outputAtBlock te da la raíz de salida para un bloque L2 específico.

Un patrón práctico es leer el bloque L2 con eth_getBlockByNumber, luego leer optimism_syncStatus para conocer los orígenes L1 actuales de cada cabeza, y después usar optimism_outputAtBlock para el bloque específico que te interesa. Esto te permite afirmar, para cualquier bloque L2, de qué bloque L1 se deriva y si actualmente es unsafe, safe o finalized.

Si usas un endpoint gestionado, el namespace rollup puede estar expuesto en la misma URL que el RPC de ejecución L2, o en una URL de op-node separada. Consulta la documentación de tu proveedor. La página de OnFinality Endpoints RPC de Base (RPC Assistant) describe los endpoints de Base disponibles, y la página de la red Base cubre el contexto de la red.

  • eth_getBlockByNumber: marca de tiempo, número, hash y transacciones del bloque L2.
  • optimism_syncStatus: cabezas L2 unsafe/safe/finalized y orígenes L1.
  • optimism_outputAtBlock: raíz de salida y referencia de bloque para un bloque L2.
  • El namespace rollup puede estar en el mismo endpoint o en uno separado; verifícalo con tu proveedor.

Lector Node.js ejecutable: mapear un bloque L2 a su origen L1

El siguiente script de Node.js lee un bloque L2 por número, luego lee optimism_syncStatus para obtener los orígenes L1 de las cabezas unsafe, safe y finalized, y finalmente lee optimism_outputAtBlock para el bloque específico. Imprime la marca de tiempo del bloque L2, el número de bloque y la marca de tiempo del origen L1, y la latencia de inclusión L1 a L2 en segundos.

Configura BASE_L2_RPC_URL con tu endpoint de ejecución L2 y BASE_ROLLUP_RPC_URL con tu endpoint rollup de op-node. Si tu proveedor expone ambos namespaces en una sola URL, configura ambas variables con el mismo valor. El script usa solo el fetch integrado disponible en Node.js moderno.

// map-l2-to-l1-origin.js
// Usage: BASE_L2_RPC_URL=... BASE_ROLLUP_RPC_URL=... node map-l2-to-l1-origin.js 12345678

const L2_URL = process.env.BASE_L2_RPC_URL;
const ROLLUP_URL = process.env.BASE_ROLLUP_RPC_URL || L2_URL;
const blockNumber = process.argv[2] ? parseInt(process.argv[2], 10) : null;

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

async function main() {
  if (blockNumber === null) throw new Error('Pass an L2 block number');

  const l2Block = await rpc(L2_URL, 'eth_getBlockByNumber', [
    '0x' + blockNumber.toString(16), false
  ]);
  if (!l2Block) throw new Error('L2 block not found');

  const sync = await rpc(ROLLUP_URL, 'optimism_syncStatus', []);
  const output = await rpc(ROLLUP_URL, 'optimism_outputAtBlock', [
    '0x' + blockNumber.toString(16)
  ]);

  const l2Ts = parseInt(l2Block.timestamp, 16);
  const l1Origin = output.blockRef ? output.blockRef.l1origin : null;
  const l1Number = l1Origin ? parseInt(l1Origin.number, 16) : null;
  const l1Ts = l1Origin ? parseInt(l1Origin.timestamp, 16) : null;

  console.log('L2 block number:', blockNumber);
  console.log('L2 block hash:', l2Block.hash);
  console.log('L2 timestamp:', l2Ts, new Date(l2Ts * 1000).toISOString());
  console.log('L1 origin number:', l1Number);
  console.log('L1 origin timestamp:', l1Ts, l1Ts ? new Date(l1Ts * 1000).toISOString() : null);
  if (l1Ts !== null) {
    console.log('L1-to-L2 inclusion latency (s):', l2Ts - l1Ts);
  }
  console.log('Unsafe L2 head:', sync.unsafe_l2 ? sync.unsafe_l2.number : null);
  console.log('Safe L2 head:', sync.safe_l2 ? sync.safe_l2.number : null);
  console.log('Finalized L2 head:', sync.finalized_l2 ? sync.finalized_l2.number : null);
}

main().catch((err) => { console.error(err); process.exit(1); });

Tabla de resultados: medir la latencia de inclusión L1 a L2 en tu endpoint

Usa el script anterior para muestrear varios bloques L2 y registrar los resultados. La tabla a continuación está intencionalmente vacía; complétala con valores medidos contra tu propio endpoint. No trates ninguna muestra individual como un benchmark. La latencia varía con el tiempo de bloque de L1, la cadencia de envío de lotes y el bloque que elijas.

Para cada fila, registra el número de bloque L2, la marca de tiempo L2, el número de origen L1, la marca de tiempo del origen L1 y la diferencia en segundos. Registra también si el bloque era unsafe, safe o finalized en el momento de la medición. Repite la medición en diferentes momentos para ver cómo se mueven los valores.

  • Número de bloque L2: el bloque que consultaste.
  • Marca de tiempo L2: de eth_getBlockByNumber.
  • Número de origen L1: de optimism_outputAtBlock blockRef.l1origin.number.
  • Marca de tiempo del origen L1: de optimism_outputAtBlock blockRef.l1origin.timestamp.
  • Latencia de inclusión L1 a L2 (s): marca de tiempo L2 menos marca de tiempo del origen L1.
  • Estado de procedencia: unsafe, safe o finalized en el momento de la medición.

Por qué la indexación solo por marca de tiempo se rompe ante reorgs

Una reorg en L1 puede cambiar qué bloques L2 se derivan de qué bloque L1. Si indexas datos L2 solo por marca de tiempo, una reorg puede reasignar tu índice silenciosamente: el mismo segundo de reloj de pared puede corresponder a un bloque L2 diferente después de la reorg. Sin un ancla de origen L1, no puedes saber si un bloque L2 dado sigue siendo canónico.

Anclar al origen L1 hace que el mapeo sea reproducible. Cuando almacenas el número de bloque de origen L1 junto al bloque L2, puedes volver a verificar la derivación después de una reorg y detectar que la procedencia del bloque L2 cambió. Esto es especialmente importante para aplicaciones que concilian depósitos, retiros o pruebas de estado.

El artículo Finalidad de Base OP-Stack: etiquetas de bloque safe, finalized y latest explica cómo se relacionan las etiquetas safe y finalized con la derivación, y el artículo Verificar el estado de sincronización del nodo Base OP-Stack cubre la lectura del estado de sincronización con más profundidad.

  • Índice solo por marca de tiempo: el mismo segundo puede mapear a diferentes bloques L2 después de una reorg.
  • Ancla de origen L1: te permite volver a verificar la derivación y detectar cambios de procedencia.
  • Crítico para depósitos, retiros y pruebas de estado que deben conciliar con L1.

Procedencia unsafe, safe y finalized: qué garantiza cada una

Los bloques L2 unsafe son producidos por el secuenciador y aún no han sido derivados de L1. Son rápidos pero pueden reorganizarse. Los bloques L2 safe han sido derivados de lotes de L1 y se consideran seguros contra reorgs de L1 hasta el punto de derivación. Los bloques L2 finalized se derivan de bloques L1 que a su vez están finalizados, lo que da la garantía más fuerte.

optimism_syncStatus expone las tres cabezas con sus orígenes L1. Cuando lees un bloque L2, debes registrar en qué cabeza está o por debajo de cuál. Un bloque en o por debajo de la cabeza finalized tiene la procedencia más fuerte; un bloque por encima de la cabeza safe pero en o por debajo de la cabeza unsafe aún está sujeto a cambios.

Para un tratamiento más profundo de las etiquetas, consulta el artículo de finalidad de Base OP-Stack. Para la mecánica del estado de sincronización, consulta el artículo de estado de sincronización del nodo.

  • Unsafe: producido por el secuenciador, aún no derivado, puede reorganizarse.
  • Safe: derivado de lotes de L1, seguro contra reorgs de L1 hasta el punto de derivación.
  • Finalized: derivado de bloques L1 finalizados, garantía más fuerte.
  • Registra el nivel de cabeza para cada bloque L2 que indexes.

Limitaciones y compensaciones de la procedencia por origen L1

Leer la procedencia L1 vía RPC añade llamadas y complejidad. optimism_syncStatus y optimism_outputAtBlock son métodos del namespace rollup; pueden no estar disponibles en todos los endpoints, y pueden tener límites de tasa diferentes a los de los métodos L2 estándar. Verifica la disponibilidad con tu proveedor antes de depender de ellos en producción.

La procedencia también es un objetivo móvil. Un bloque que ahora es unsafe puede volverse safe más tarde, y un bloque que ahora es safe puede volverse finalized más tarde. Si almacenas en caché la procedencia, debes volver a verificarla. Los reinicios del secuenciador también pueden afectar la cabeza unsafe: tras un reinicio, el secuenciador puede re-derivar o re-producir bloques, y la cabeza unsafe puede moverse.

Finalmente, la latencia de inclusión L1 a L2 no es un valor fijo. Depende del tiempo de bloque de L1, la cadencia de envío de lotes y el bloque específico. No trates ninguna medición individual como un benchmark. Mide contra tu propio endpoint y registra las condiciones.

  • El namespace rollup puede no estar disponible o tener límites de tasa en algunos endpoints.
  • El estado de procedencia cambia con el tiempo; los valores en caché deben volver a verificarse.
  • Los reinicios del secuenciador pueden mover la cabeza unsafe.
  • La latencia de inclusión varía; mide, no asumas.

Solución de problemas comunes de RPC de procedencia

Si optimism_syncStatus devuelve un error de método no encontrado, tu endpoint probablemente no expone el namespace rollup. Prueba una URL de op-node dedicada o consulta la documentación de tu proveedor. La página de OnFinality Endpoints RPC de Base (RPC Assistant) lista los endpoints de Base disponibles y sus namespaces.

Si optimism_outputAtBlock devuelve un error para un número de bloque, el bloque puede estar por encima de la cabeza unsafe actual, o el op-node puede no haberlo derivado todavía. Reintenta tras un breve retraso, o consulta un número de bloque inferior. Si faltan los campos de origen L1, confirma que estás leyendo correctamente el objeto blockRef; los nombres de campo distinguen mayúsculas y minúsculas.

Si la marca de tiempo de tu bloque L2 es anterior a la marca de tiempo del origen L1, probablemente estás confundiendo las dos marcas de tiempo o leyendo un bloque obsoleto. Vuelve a leer ambos valores y compáralos. Si la discrepancia persiste, verifica si tu endpoint está sirviendo una cadena diferente o una respuesta en caché.

  • Método no encontrado: el namespace rollup no está expuesto; prueba una URL de op-node dedicada.
  • Bloque no encontrado: el bloque puede estar por encima de la cabeza unsafe o aún no derivado; reintenta o baja el bloque.
  • Campos de origen L1 faltantes: verifica los nombres de campo de blockRef y las mayúsculas/minúsculas.
  • Inversión de marcas de tiempo: vuelve a leer ambas marcas de tiempo; busca respuestas obsoletas o en caché.

Prácticas operativas para indexación consciente de la procedencia

Almacena el número de bloque de origen L1 y la marca de tiempo del origen L1 junto a cada bloque L2 que indexes. Esto te permite volver a verificar la derivación después de una reorg y detectar cambios de procedencia. También te permite calcular la latencia de inclusión de forma consistente en todo tu conjunto de datos.

Consulta optimism_syncStatus periódicamente y registra las cabezas unsafe, safe y finalized. Cuando leas un bloque L2, compara su número con esas cabezas y registra el estado de procedencia. Esto te da una forma reproducible de clasificar bloques sin depender solo de las marcas de tiempo.

Para datos históricos, usa un endpoint de archivo. El artículo Nodo de archivo de Base y RPC histórico explica el acceso de archivo, y el artículo Tarifa de datos L1 y costo de transacción de OP-Stack cubre la contabilidad de tarifas que también depende de los datos L1. Para la conciliación de depósitos y retiros, consulta Rastrear registros de depósitos entre cadenas y pruebas de retiro de Base.

  • Almacena el número de origen L1 y la marca de tiempo con cada bloque L2.
  • Consulta optimism_syncStatus y registra los niveles de cabeza.
  • Clasifica los bloques por estado de procedencia, no solo por marca de tiempo.
  • Usa endpoints de archivo para consultas de procedencia histórica.

Próximos pasos: finalidad, estado de sincronización y contexto de tarifas

Para profundizar, lee el artículo de finalidad de Base OP-Stack para las etiquetas safe y finalized, y el artículo de estado de sincronización del nodo para la mecánica del estado de sincronización. Juntos explican cómo las cabezas que lees en optimism_syncStatus se relacionan con la derivación y la finalidad.

Para trabajo de costos y conciliación, consulta el artículo de tarifa de datos L1 de OP-Stack y el artículo de pruebas de depósito y retiro. Para consultas históricas, consulta el artículo de nodo de archivo de Base.

Si estás eligiendo un endpoint, comienza por la página de la red Base y la página de Endpoints RPC de Base (RPC Assistant). Para detalles de precios y servicio, consulta Precios de RPC y la página de Servicio de API. El hub de aprendizaje de OnFinality reúne el conjunto completo de guías.

  • Etiquetas de finalidad: safe, finalized, latest.
  • Estado de sincronización: cabezas unsafe, safe, finalized y orígenes L1.
  • Tarifas: la tarifa de datos L1 depende de la disponibilidad de datos L1.
  • Conciliación: los depósitos y retiros necesitan anclas de origen L1.

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