Ethereum: de historia a labs
Artículo 46 de 48
96%
completado al llegar aquí
Datos y observabilidadNota de investigación11 min de lectura
Observabilidad Ethereum para dApps
Qué medir en una dApp Ethereum: atraso del RPC, del indexador y de la finalidad, ciclo de vida de transacciones y conciliación del índice contra la cadena.
Ruta Ethereum: 0/48
Prerequisitos recomendados
Si alguno de estos conceptos todavía está medio nebuloso, empieza por aquí. Te ahorra tropiezos y un par de cejas fruncidas.
Indexadores: eventos, reorgs e idempotencia
Cómo indexar logs de Ethereum que sobreviven reintentos, backfills y reorgs: cursor con hash, etiquetas safe y finalized, y efectos idempotentes.
Blockchain14 min de lectura→Clientes y nodos: diversidad antes que monocultivo
Qué corre dentro de un nodo Ethereum: cliente de ejecución, cliente de consenso y Engine API, y por qué ningún cliente debería superar un tercio de la red.
Blockchain12 min de lectura→
Un cliente escribe a soporte: "Envié el depósito hace diez minutos y mi saldo no cambia". Abres los paneles. El servicio responde, la base de datos está sana, el proveedor de RPC no reporta errores. Todo en verde. Y sin embargo el cliente tiene razón. ¿Dónde miras?
Una dApp (aplicación descentralizada: contratos en la cadena más servicios y una interfaz fuera de ella) tiene más relojes que un backend tradicional, y cada uno puede atrasarse sin que nada "falle". Este capítulo propone qué medir para que esa pregunta tenga respuesta en minutos: atrasos entre relojes, el ciclo de vida de cada transacción y una conciliación periódica entre tu índice y la cadena.
Flujo visual
Del síntoma a la capa
Brújula de lectura
Actor, evidencia y estado
Actor
Operador de la dAppQuien recibe la alerta y tiene que decidir en qué capa está el problema.
Evidencia
Números de bloque y recibosCada reloj se mide en bloques o slots, y cada transacción deja un recibo con status.
Estado
Atrasos entre relojesLo que se vigila no es cada sistema por separado, sino la distancia entre ellos.
Preguntas guía
Estas preguntas son las que un operador debería poder responder con los paneles, sin abrir el código:
- ¿Cuántos bloques está atrasado tu proveedor de RPC respecto de otra fuente?
- ¿Cuánto tiempo pasa entre el bloque
latesty elfinalized, y es normal hoy? - ¿Cuántos bloques le faltan a tu indexador para alcanzar la etiqueta que usa tu política?
- De las transacciones que enviaste en la última hora, ¿cuántas siguen pendientes y cuántas terminaron con status 0?
- ¿Coinciden los saldos de tu índice con los que da la cadena en el bloque
finalized?
Conexiones dentro de la serie
- Antes: Clientes y nodos: diversidad antes que monocultivo, con las comprobaciones de salud de un nodo.
- Después: Arquitectura production-ready para dApps, que usa estas métricas para decidir cuándo liberar fondos.
Prerequisitos internos recomendados:
- Indexadores: eventos, reorgs e idempotencia, para el cursor y las etiquetas de bloque.
- Una transacción Ethereum por dentro, para nonce, gas y recibos.
Cuello de botella: cuatro relojes que pueden ir atrasados
Una dApp combina al menos cuatro relojes. El de la red: la cabeza de la cadena avanza a lo sumo un bloque por slot de 12 segundos, y algunos slots quedan vacíos. [3] El de tu proveedor de RPC, que ve la cabeza con algún retraso. El de tu indexador, cuyo cursor va detrás del proveedor. Y el de la interfaz, que puede mostrar datos de una caché.
Cada reloj puede estar sano por separado y la experiencia rota en conjunto. El saldo del ejemplo inicial puede no aparecer porque el proveedor dejó de avanzar, porque el indexador se detuvo en una reorg, o porque tu política espera finalized y la finalidad está tardando más de lo habitual.
Por eso las métricas útiles son diferencias, no valores absolutos:
- Atraso del RPC: número de bloque
latestde una fuente de referencia menos el de tu proveedor. Si usas dos fuentes, compara las dos. - Atraso de finalidad:
latestmenosfinalized. Hoy un bloque tarda unos 15 minutos en finalizar; un valor muy por encima indica un problema de la red, no tuyo. [4] - Atraso del indexador: la etiqueta que usa tu política (
safeofinalized) menos la altura del cursor. - Profundidad de reorg: cuántos bloques retrocedió el indexador en cada reorg. Es un contador, no un estado.
Las etiquetas latest, safe y finalized están definidas en la especificación de las APIs de ejecución y se piden con eth_getBlockByNumber. [1]
Cuatro relojes de una dApp y las distancias que conviene medir
Cómo leer esta figura
Un eje horizontal de alturas de bloque que crece hacia la derecha. En él se marcan finalized, safe y latest de la red de referencia. Debajo, cuatro carriles: red, proveedor RPC, indexador e interfaz. El proveedor marca su latest un poco antes del latest de la red; la distancia se rotula atraso del RPC. El cursor del indexador está antes de safe; la distancia se rotula atraso del indexador. La distancia entre finalized y latest se rotula atraso de finalidad. La interfaz muestra un dato de caché aún más atrás.
Traza de ejecución de una transacción vista por métricas
Las transacciones que tu dApp envía también tienen un reloj propio. Conviene registrar cada transición con marca de tiempo y el hash de la transacción como identificador común:
- Enviada.
eth_sendRawTransactiondevuelve el hash. Que el nodo la acepte no significa que vaya a entrar en un bloque. - Pendiente. No hay recibo todavía. La métrica es el tiempo en este estado; si crece, revisa las comisiones ofrecidas.
- Incluida.
eth_getTransactionReceiptdevuelve un recibo conblockNumber,blockHash,gasUsed,effectiveGasPriceystatus. - Resultado.
statusvale 1 si tuvo éxito y 0 si falló. Una transacción con status 0 está incluida, cobró gas y no cambió el estado del contrato. - Asentada. El bloque del recibo alcanza
safey luegofinalized.
El campo status existe desde Byzantium gracias a EIP-658: antes, al introducirse el opcode REVERT, ya no se podía deducir que una transacción había fallado solo porque consumía todo el gas. [6] Mide la tasa de status 0 por contrato y por función: un salto suele indicar un cambio en el contrato, en los parámetros o en el estado del mercado.
El costo real también se observa. Con EIP-1559, el emisor fija maxFeePerGas y maxPriorityFeePerGas, y el precio efectivo es la base del bloque más la propina, con la propina limitada para no superar el máximo: . [5] El recibo trae ese valor en effectiveGasPrice, y eth_feeHistory devuelve la base y las propinas efectivas de un rango de bloques para comparar lo que pagaste con lo que pagaba la red. [1]
Invariante de conciliación: el índice contra la cadena
Las métricas de atraso dicen si tu índice va al día. No dicen si es correcto. Para eso hace falta una conciliación: comparar periódicamente lo que dice tu índice con lo que dice la cadena, en un bloque que no va a cambiar.
El invariante es simple: para cada cuenta vigilada, el saldo de tu índice en el bloque finalized es igual al resultado de balanceOf(cuenta) ejecutado con eth_call en ese mismo bloque. Un desajuste indica un evento perdido, uno aplicado dos veces, un efecto de una rama huérfana o un token cuyo saldo cambia sin emitir Transfer. Cualquiera de los cuatro merece una alerta con nombre propio.
El fragmento es ilustrativo (Node 18 o superior, sin librerías). Calcula los atrasos de la sección anterior; la función emit representa tu exportador de métricas.
// Ilustrativo: atrasos entre relojes. emit() es tu exportador de métricas.
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 { result, error } = await res.json();
if (error) throw new Error(`${method}: ${error.message}`);
return result;
}
const height = async (url, tag) =>
Number((await rpc(url, 'eth_getBlockByNumber', [tag, false])).number);
async function sample({ providerUrl, referenceUrl, indexerCursor }) {
const [refLatest, provLatest, provSafe, provFinalized] = await Promise.all([
height(referenceUrl, 'latest'),
height(providerUrl, 'latest'),
height(providerUrl, 'safe'),
height(providerUrl, 'finalized'),
]);
emit('rpc_head_lag_blocks', refLatest - provLatest);
emit('finality_lag_blocks', provLatest - provFinalized);
emit('indexer_lag_blocks', provSafe - (await indexerCursor()));
}Riesgo operativo: alertas que llevan a una acción
Una alerta sin acción entrena al equipo a ignorarla. La regla práctica: cada alerta nombra la capa, el umbral y el primer paso del procedimiento. Los umbrales concretos dependen de tu política de confirmación y de tu tráfico; los de la tabla son puntos de partida a revisar, no valores del protocolo.
Síntoma, señal y primera acción
Reglas de decisión rápida
El RPC va atrasado
rpc_head_lag_blocks sostenido sobre unos pocos bloques
→ Pasar lecturas a la fuente secundaria y abrir incidencia con el proveedor.
La finalidad se detuvo
finality_lag_blocks crece en todas las fuentes a la vez
→ Congelar retiros que dependen de finalized y comunicar; no cambiar la política en silencio.
El indexador no avanza
indexer_lag_blocks crece mientras el RPC está al día
→ Revisar errores del bucle, reorgs profundas o límites de rango en eth_getLogs.
Suben los status 0
tasa de recibos fallidos por función
→ Simular la llamada con eth_call contra el estado actual y revisar cambios del contrato.
La conciliación no cuadra
saldo indexado distinto de balanceOf en finalized
→ Bloquear movimientos de esa cuenta y reprocesar desde el último bloque conciliado.
Para el nodo propio, la Beacon API ofrece un endpoint pensado para balanceadores: /eth/v1/node/health responde 200 si el nodo está listo, 206 si está sincronizando o su cliente de ejecución está en modo optimista o fuera de línea, y 503 si tiene problemas. [2] Úsalo para sacar un nodo del pool de lecturas, no como sustituto de las métricas de atraso.
Cuándo una dApp está sana
Quédate con una frase: una dApp no está sana porque el contrato compila y los servicios responden; está sana cuando las distancias entre relojes son normales, cada transacción tiene un estado conocido y el índice cuadra con la cadena en finalized.
Bibliografía académica
- [1]
Ethereum Execution APIs specification.
Etiquetas de bloque, recibos, effectiveGasPrice y eth_feeHistory.
- [2]
Ethereum Beacon APIs specification.
Endpoint /eth/v1/node/health y sus códigos.
- [3]
ethereum.org, "Proof-of-stake (PoS)."
Slots de 12 segundos, epochs de 32 slots y finalidad.
- [4]
ethereum.org, "Single slot finality."
Tiempo actual hasta finalidad, alrededor de 15 minutos.
- [5]
V. Buterin, E. Conner, R. Dudley, M. Slipper, I. Norden, and A. Bakhta, "EIP-1559: Fee market change for ETH 1.0 chain," Ethereum Improvement Proposals, 2019.
Base fee, propina y precio efectivo.
- [6]
N. Johnson, "EIP-658: Embedding transaction status code in receipts," Ethereum Improvement Proposals, 2017.
Campo status en recibos.
Rutas vecinas
Si este tema te abrió hambre, sigue por aquí.
Series y labs que comparten área o dependen de esta ruta. Pocas opciones, para no convertir la curiosidad en menú infinito.
Labs para convertir lectura en práctica
Ethereum local: Anvil, wallet y primera transacción
Laboratorio base para levantar una red local, crear cuentas, firmar transacciones y observar receipts sin gastar ETH real.
RPC y Cast: leer Ethereum con lupa
Ejercicios con JSON-RPC y Cast para consultar bloques, nonces, gas, receipts, logs y errores reproducibles.
ERC-20 con Foundry: estándar, tests e invariantes
Construcción de un token ERC-20 mínimo con pruebas unitarias, fuzzing básico, allowances y escenarios de aprobación riesgosa.
Storage layout: ver slots antes de romper upgrades
Laboratorio para inspeccionar slots, packing, mappings y colisiones de storage en contratos upgradeables.
Sigue leyendo
Ideas conectadas con este artículo
Una ruta corta para continuar sin abrir veinte pestañas y perder el hilo.
Indexadores: eventos, reorgs e idempotencia
Cómo consumir logs, manejar confirmations, backfills, replays y reorgs sin inventar exactly-once.
Clientes y nodos: diversidad antes que monocultivo
Execution clients, consensus clients, node operators, client diversity, APIs y por qué Ethereum no debe depender de una sola implementación.
Arquitectura production-ready para dApps
Checklist arquitectónico para llevar una dApp a producción: wallet UX, RPC fallback, contratos, indexadores, monitoreo, seguridad e incident response.
Ethereum: mapa de lectura antes de tocar Solidity
Ruta completa para aprender Ethereum desde historia y arquitectura hasta EVM, proof-of-stake, L2, seguridad, DeFi y labs reproducibles.