Datos en cadena y SQL · Lección 1 de 9
Bloques, encabezados y API de nodos
14 min de lectura
Los bloques son la forma en que una blockchain registra el tiempo y el orden, por lo que toda cronología, total diario y afirmación de «antes o después» en un caso depende de interpretarlos correctamente. La parte más reciente de cualquier cadena es provisional: los bloques cercanos al extremo de la cadena pueden ser reemplazados. Detrás de cada explorador, conjunto de datos y plataforma de análisis hay un nodo que responde a llamadas a la API. Un investigador que sabe qué contiene un encabezado, hasta qué punto puede confiar en su marca de tiempo, cuándo es seguro basarse en un bloque y qué llamada al nodo produjo una cifra puede evitar que los datos provisionales se incluyan en los hallazgos y verificar lo que muestra una herramienta de terceros.
Qué contiene un encabezado
Un encabezado de bloque es un registro pequeño que resume el bloque y lo vincula con su bloque padre. Un encabezado de Bitcoin tiene exactamente 80 bytes y seis campos:
| Campo | Tamaño | Significado para el analista |
|---|---|---|
| versión | 4 bytes | Conjunto de reglas y bits de señalización de bifurcaciones suaves |
| hash del bloque anterior | 32 bytes | Vínculo con el padre; la cadena se construye a partir de estos vínculos |
| raíz de Merkle | 32 bytes | Compromiso criptográfico con todas las transacciones del bloque |
| tiempo | 4 bytes | Marca de tiempo Unix elegida por el minero |
| bits | 4 bytes | Codificación compacta del objetivo de dificultad |
| nonce | 4 bytes | Valor que los mineros modifican para encontrar un hash válido |
El hash del bloque no es un campo del encabezado. Es el doble SHA-256 de los 80 bytes del encabezado, y los exploradores lo muestran con el orden de los bytes invertido, por lo que comienza con ceros. El método getblock de Bitcoin Core añade valores derivados como height, mediantime, chainwork y confirmations.
Un encabezado de Ethereum también incluye compromisos criptográficos con el estado y los recibos. Los campos que más utilizan los analistas son:
| Campo | Significado |
|---|---|
number, parentHash | Altura y vínculo con el padre |
timestamp | Tiempo Unix en segundos |
miner | Destinatario de las comisiones elegido por el proponente del bloque (el nombre es anterior a la prueba de participación) |
stateRoot, transactionsRoot, receiptsRoot | Compromisos criptográficos con el estado, las transacciones y los recibos |
logsBloom | Filtro de Bloom que permite a los clientes omitir bloques sin registros coincidentes |
gasLimit, gasUsed, baseFeePerGas | Capacidad, uso y comisión base quemada por unidad de gas (London, agosto de 2021) |
withdrawalsRoot | Retiros de los validadores (Shanghai, abril de 2023) |
blobGasUsed, excessBlobGas, parentBeaconBlockRoot | Contabilidad de blobs y vínculo con el consenso (Cancun, marzo de 2024) |
requestsHash | Solicitudes de la capa de ejecución a la de consenso, EIP-7685 (Prague, mayo de 2025) |
Los campos aparecen solo a partir de la actualización que los introdujo, por lo que una canalización de datos debe admitir su ausencia en bloques más antiguos. Desde la Fusión, difficulty y nonce son cero y mixHash contiene el valor de aleatoriedad de la cadena de baliza. Los datos anteriores a la Fusión también contienen bloques ommer (tíos): bloques válidos que perdieron una carrera, pero a los que un bloque posterior hizo referencia mediante sha3Uncles y la lista uncles. Sus mineros recibían una recompensa reducida sin ninguna transacción, por lo que el análisis de recompensas de la era de la minería debe incluirlos.
Altura frente a hash
La altura (number en Ethereum) es una posición: el número de bloques desde el génesis. El hash del bloque es una identidad. Dos bloques pueden compartir una altura cuando la cadena se bifurca, y solo uno termina en la cadena principal; un hash identifica exactamente un bloque para siempre. Utilice la altura para los rangos («bloques del 21.000.000 al 21.000.999») y el hash como clave de almacenamiento. En un informe, cite ambos: «altura 880.214, hash 0000…3f1a». El método getblockhash de Bitcoin devuelve el hash que se encuentra actualmente en una altura, que puede cambiar cerca del extremo de la cadena.
Marcas de tiempo y su fiabilidad
La marca de tiempo de un bloque es la hora que un analista asigna a todas las transacciones que contiene.
En Bitcoin, el minero establece las marcas de tiempo conforme a dos reglas: el tiempo debe ser mayor que la mediana de los 11 bloques anteriores (la mediana del tiempo pasado), y los nodos rechazan bloques que se adelanten más de dos horas a su propio reloj (las versiones anteriores de Bitcoin Core utilizaban un tiempo «ajustado a la red» a partir de los pares). Por tanto, un bloque puede tener una marca de tiempo anterior a la de su padre, y cualquier marca de tiempo individual puede desviarse una hora o más. Utilice la altura para establecer el orden; mediantime nunca disminuye y sirve como reloj monótono. Indique los tiempos de Bitcoin solo con la precisión que permitan los datos.
Desde la Fusión (septiembre de 2022), Ethereum tiene intervalos fijos de 12 segundos: la marca de tiempo de un bloque es igual al tiempo del génesis más 12 segundos multiplicados por su número de intervalo. Una separación de 24 o 36 segundos entre bloques consecutivos significa que uno o dos intervalos no tuvieron bloque. Antes de la Fusión, los mineros establecían las marcas de tiempo con reglas menos estrictas; en los rollups, el secuenciador las establece según las reglas propias de cada rollup.
Hay dos advertencias que se aplican en todos los casos. El tiempo del bloque indica cuándo se incluyó una transacción, no cuándo se firmó o difundió. Además, las horas de «primera observación» que muestran los exploradores proceden de sus propios observadores del mempool: son indicios útiles, pero locales a un único observador.
Reorganizaciones y finalidad
Una reorganización (reorg) se produce cuando los nodos cambian a una rama competidora. Los bloques reemplazados quedan obsoletos o, en el uso común, huérfanos. En Bitcoin, los nodos siguen la rama con más trabajo acumulado (chainwork); las transacciones de un bloque obsoleto suelen reaparecer en la rama ganadora, posiblemente en un bloque y una posición diferentes, o no reaparecen en absoluto si se confirmó en su lugar una transacción en conflicto. getchaintips enumera las ramas conocidas, y getblock indica un valor de confirmations de −1 para un bloque que no está en la cadena principal. En Ethereum, la prueba de participación hace que las reorganizaciones sean menos frecuentes y que, por lo general, tengan una profundidad de un bloque; los registros entregados mediante suscripciones o filtros incluyen removed: true cuando una reorganización los descarta.
La finalidad es el punto en el que un bloque puede tratarse como permanente. La finalidad de Bitcoin es probabilística: cada confirmación hace que reemplazarlo sea exponencialmente más costoso, seis es una convención habitual para las transferencias de valor, y las salidas coinbase no pueden gastarse durante 100 bloques. Ethereum tiene finalidad económica explícita: los intervalos forman épocas de 32 intervalos (6,4 minutos), y los puntos de control pasan a estar justificados y luego finalizados, normalmente después de unas dos épocas (aproximadamente 13 minutos). Revertir un bloque finalizado requeriría que se destruyera al menos un tercio de todo el ETH en participación.
La API JSON-RPC de Ethereum expone esto mediante etiquetas de bloque que se aceptan en lugar de un número: earliest, latest, safe, finalized y pending. Lo que devuelve safe depende del cliente de consenso (a menudo, el último punto de control justificado, aunque algunos clientes lo sitúan a pocos segundos de la cabecera de la cadena), así que compruebe su nodo en lugar de darlo por hecho.
| Uso | Bitcoin | Ethereum |
|---|---|---|
| Alertas en tiempo real | 0–1 confirmaciones, con gestión de reorganizaciones | latest, con gestión de reorganizaciones |
| Decisiones operativas | Profundidad definida por la política, a menudo 3–6 | safe o finalized |
| Informes y estadísticas | Mucho más de 6, o un límite antiguo fijo | finalized |
Gestión de datos huérfanos
Una canalización de datos robusta almacena el hash y el hash del padre de cada bloque, comprueba con cada bloque nuevo que el hash de su padre coincide con el hash almacenado una altura por debajo y, cuando no coincide, retrocede hasta el ancestro común, incorpora la nueva rama y mueve las filas reemplazadas a una tabla de auditoría en lugar de eliminarlas. Las consultas siguientes utilizan el esquema genérico de la lección 2.7, donde blocks contiene la cadena canónica y transactions incluye su block_hash:
-- Recuentos diarios de transacciones, nunca más allá del bloque finalizado
SELECT DATE_TRUNC('day', b.block_timestamp) AS day_utc,
COUNT(*) AS tx_count
FROM transactions t
JOIN blocks b ON b.hash = t.block_hash -- hash, no altura: excluye filas de bloques obsoletos
WHERE b.number <= :finalized_block -- de eth_getBlockByNumber("finalized", false)
GROUP BY DATE_TRUNC('day', b.block_timestamp)
ORDER BY day_utc;
-- Bloques cuyo padre falta: lagunas o reorganizaciones no gestionadas
SELECT c.number, c.hash, c.parent_hash
FROM blocks c
LEFT JOIN blocks p ON p.hash = c.parent_hash
WHERE p.hash IS NULL
AND c.number > (SELECT MIN(number) FROM blocks);
La tabla de auditoría es importante en el trabajo con casos. Suponga que un exchange abonó un depósito después de una confirmación, el bloque quedó obsoleto y se confirmó en su lugar una transacción en conflicto que gastaba las mismas monedas. Una página almacenada en la caché de un explorador puede seguir mostrando la primera transacción; solo los datos almacenados del bloque obsoleto explican por qué un depósito «confirmado» nunca existió en la cadena definitiva.
Lectura de la cadena mediante las API de nodos
Bitcoin Core expone JSON-RPC (un POST HTTP con un method y un arreglo params, autenticado mediante un archivo de cookie o un usuario configurado), también disponible a través de bitcoin-cli. Los importes se devuelven en BTC como números JSON. Los clientes de ejecución de Ethereum (Geth, Nethermind, Besu, Erigon, Reth) implementan una especificación JSON-RPC común, y la mayoría de las cadenas EVM, los rollups y las cadenas laterales ofrecen la misma interfaz. Las cantidades son cadenas hexadecimales ("0x1b4"); los espacios de nombres como debug_ y trace_ son específicos de cada cliente.
Métodos de Bitcoin Core
| Método | Devuelve | Notas |
|---|---|---|
getblockchaininfo | Cadena, altura, mejor hash, estado de poda | Primera llamada de cualquier sesión |
getblockhash height / getblockheader hash | Hash en una altura / encabezado y confirmations | El hash puede cambiar cerca del extremo de la cadena |
getblock hash verbosity | 0: hexadecimal; 1: encabezado e identificadores de transacción; 2: transacciones decodificadas con comisiones; 3: añade prevout por entrada | Las comisiones y las salidas previas requieren datos de deshacer |
getrawtransaction txid verbosity | 0: hexadecimal; 1: decodificada; 2: añade comisión y salidas previas | Las transacciones confirmadas requieren txindex=1 o un hash de bloque |
gettxout txid n | Detalles de la salida si actualmente no está gastada | Null si está gastada o es desconocida |
gettxspendingprevout | Transacción que gasta las salidas indicadas | Solo mempool, salvo que esté habilitado txospenderindex (31.0 y posteriores) |
getchaintips | Ramas conocidas y su estado | Investigación de reorganizaciones |
Una secuencia típica para examinar un pago:
getblockhash 880214 -> "0000…3f1a"
getblock "0000…3f1a" 1 -> campos del encabezado y lista de identificadores de transacción
getrawtransaction "4f3a…c21e" 2 -> transacción decodificada con valores de prevout y comisión
gettxout "4f3a…c21e" 1 -> salida 1 si aún no está gastada; de lo contrario, null
gettxout indica si una salida está sin gastar ahora, no cuándo ni mediante qué se gastó. Bitcoin Core no tiene ningún método que enumere el historial de una dirección; para ello se necesita un indexador de direcciones o un almacén de datos.
Métodos de Ethereum
| Método | Devuelve |
|---|---|
eth_chainId | ID de cadena (EIP-695): confirma en qué red se encuentra |
eth_blockNumber, eth_getBlockByNumber, eth_getBlockByHash | Última altura; encabezado con hashes de transacciones, o transacciones completas cuando el segundo parámetro es true |
eth_getTransactionByHash, eth_getTransactionReceipt | Transacción firmada con from recuperado; estado, gas y registros |
eth_getBlockReceipts | Todos los recibos de un bloque en una sola llamada |
eth_getLogs | Registros que coinciden con un filtro |
eth_getBalance, eth_getCode, eth_getStorageAt, eth_call | Estado en un bloque determinado |
Dos comportamientos sorprenden a quienes empiezan. Un recibo con valor null significa que la transacción está pendiente o que el nodo la desconoce, no que haya fallado. Además, los métodos de estado responden para el bloque que se les pasa: eth_getBalance con latest cambia cada pocos segundos, así que pase un número de bloque explícito para cualquier cifra que incluya en un informe.
eth_getLogs recibe fromBlock y toBlock (o un único blockHash), un parámetro address opcional y un arreglo posicional topics. Esta solicitud pide a un contrato de token los eventos Transfer enviados a una dirección entre los bloques 21.000.000 (0x1406f40) y 21.000.999 (0x1407327):
{"jsonrpc": "2.0", "id": 1, "method": "eth_getLogs",
"params": [{
"fromBlock": "0x1406f40", "toBlock": "0x1407327",
"address": "0x5d3a…7c10",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
null,
"0x000000000000000000000000c3d4…22e1"]
}]}
Los temas coinciden por posición: el primero es la firma de Transfer, null acepta cualquier remitente y topics[2] fija el destinatario. Una posición también puede contener un arreglo que significa «cualquiera de estos»; mover la dirección rellenada a la segunda posición devuelve las transferencias enviadas por ella.
Métodos de depuración y trazado
Las llamadas internas requieren una nueva ejecución. Los clientes de estilo Geth ofrecen debug_traceTransaction, debug_traceBlockByNumber y debug_traceCall con un tracer como callTracer (árbol de llamadas) o prestateTracer (estado al que se accedió). Los clientes de estilo Parity (Erigon, Nethermind, Reth) ofrecen trace_transaction, trace_block, trace_filter y trace_replayTransaction, que devuelven listas planas de llamadas. Ambos tipos consumen muchos recursos, a menudo están deshabilitados o los proveedores cobran un suplemento por ellos, y difieren en su estructura (por ejemplo, en si aparecen las llamadas a precompilados), así que normalícelos antes de combinar los resultados.
Qué nodo necesita cada pregunta
| Pregunta | Bitcoin | Ethereum |
|---|---|---|
| Bloques, transacciones, recibos, registros | Nodo completo (txindex=1 para búsquedas por txid) | Nodo completo; el historial anterior a la Fusión puede haber caducado |
| Saldo actual o estado de UTXO | gettxout, o un indexador para direcciones | Nodo completo, eth_getBalance |
| Saldo en un bloque pasado | Indexador o almacén de datos | Nodo de archivo |
| Historial de direcciones | Indexador de direcciones o almacén de datos | Indexador o almacén de datos (sin método nativo) |
| Llamadas internas de transacciones antiguas | No corresponde | Nodo de archivo con trazado |
Los nodos podados no pueden proporcionar bloques antiguos en absoluto. Un nodo completo de Ethereum al que se solicita un estado anterior a su ventana de retención devuelve un error en lugar de un número incorrecto: una señal de que necesita un nodo de archivo.
Proveedores, límites de solicitudes y confianza
Los proveedores de servicios alojados aplican límites de solicitudes (solicitudes por segundo o «unidades de cómputo» ponderadas) y limitan eth_getLogs por rango de bloques, número de resultados o ambos. Una extracción robusta divide un rango en segmentos, reduce a la mitad un segmento que el proveedor rechaza, reintenta con espera exponencial y registra los rangos completados. Las solicitudes por lotes de JSON-RPC reducen la sobrecarga, pero cuentan para los mismos límites. Los proveedores también plantean cuestiones de confianza:
- Cabeceras de cadena inconsistentes. Detrás de un equilibrador de carga, las llamadas consecutivas pueden llegar a nodos situados en alturas diferentes. Fije el trabajo a un hash de bloque, no a
latest. - Errores y retrasos. Para los hechos de los que depende un hallazgo, compare el hash del bloque en su altura de referencia entre dos fuentes independientes o con su propio nodo, y registre la versión del cliente (
web3_clientVersion, o el camposubversiondegetnetworkinfo). - Privacidad de las consultas. Un proveedor ve todas las direcciones por las que pregunta; sus registros pueden revelar el objetivo de una investigación. Su propio nodo no lo hace.
Para obtener grandes volúmenes de datos históricos, la extracción mediante RPC es lenta. Los conjuntos de datos públicos (los conjuntos de datos de criptomonedas de Google BigQuery, creados con las herramientas de código abierto blockchain-etl; el conjunto AWS Public Blockchain Data en Parquet) y los marcos ETL (Ethereum ETL, Bitcoin ETL, cryo, TrueBlocks, The Graph) son las alternativas; la lección 2.7 los compara.
Enfoque del examen: espere preguntas que le pidan elegir la fuente de datos o el límite adecuados para un hallazgo: los seis campos del encabezado de Bitcoin y el hecho de que el hash del bloque se calcula; la altura como posición frente al hash como identidad; la mediana del tiempo pasado, la regla de las dos horas y las marcas de tiempo de Bitcoin fuera de orden frente a los intervalos exactos de 12 segundos de Ethereum; las reorganizaciones, los registros conremoved: truey los datos de auditoría de bloques obsoletos; las confirmaciones, las épocas y las etiquetaslatest,safeyfinalized; el nivel de detalle degetblockygetrawtransactionytxindex; las limitaciones degettxout; la coincidencia posicional de temas eneth_getLogs; los métodosdebug_frente atrace_; cuándo se necesita un nodo de archivo; la verificación de proveedores.