Datos en cadena y SQL · Lección 6 de 9
Calidad, normalización y procedencia de los datos
10 min de lectura
La mayoría de las cifras incorrectas en el análisis de cadenas de bloques no se deben a heurísticas deficientes, sino a errores de datos cotidianos: un importe desviado por un factor de 10^12, un límite de día en una zona horaria incorrecta, una transferencia contada dos veces o una transacción de Polygon incluida en los totales de Ethereum. Estos errores son fáciles de cometer y difíciles de detectar en un gráfico terminado. Esta lección presenta las reglas de normalización que los evitan y el registro de procedencia que permite a cualquiera verificar su trabajo.
Unidades: conserve los enteros hasta el final
Las cadenas de bloques almacenan los importes como números enteros de la unidad más pequeña. Los separadores decimales son una convención de visualización.
| Activo | Unidad base | Conversión |
|---|---|---|
| Bitcoin | satoshi | 1 BTC = 100.000.000 sat (10^8) |
| Ether | wei | 1 ETH = 10^18 wei; 1 gwei = 10^9 wei |
| Tokens ERC-20 | unidades sin procesar | Dividir por 10^decimals, obtenido del contrato del token |
Los decimales de los tokens varían: 18 es habitual, pero USD Coin usa 6 y Wrapped Bitcoin usa 8. El valor decimals es opcional en el estándar ERC-20 y es puramente informativo: los saldos del contrato siempre son enteros sin procesar. Léalo de cada contrato en cada cadena en lugar de darlo por supuesto, porque una versión de un token transferida mediante un puente puede diferir de la original. El costo de una suposición incorrecta es elevado: un importe sin procesar de 2.500.000.000 equivale a 2.500 tokens con 6 decimales, pero a 0,0000000025 con 18 decimales, un factor de 10^12.
De aquí se derivan dos riesgos. Primero, el punto flotante. Bitcoin Core devuelve los importes en BTC como números JSON, por ejemplo 0.00485900, y un analizador mal implementado los convierte en valores binarios de punto flotante que no pueden representar exactamente la mayoría de las fracciones decimales, por lo que las sumas presentan pequeñas desviaciones y las conciliaciones fallan. Analice los importes como cadenas decimales y conviértalos inmediatamente a satoshis enteros. Segundo, el desbordamiento. Los importes de Ethereum son enteros sin signo de 256 bits, hasta aproximadamente 1,16 × 10^77. Un BIGINT con signo de 64 bits tiene un máximo de 9.223.372.036.854.775.807, que en wei equivale a solo unos 9,22 ETH, e incluso un DECIMAL de 38 dígitos no puede contener todos los valores posibles. Almacene los importes sin procesar como texto o en un tipo numérico de gran capacidad y conviértalos en el último paso:
-- Los importes sin procesar se mantienen exactos; la conversión solo se realiza para la visualización
SELECT tt.transaction_hash,
tt.log_index,
tt.amount_raw, -- entero exacto conservado como texto
CAST(tt.amount_raw AS DECIMAL(38, 0))
/ POWER(10, tk.decimals) AS amount_display -- aproximado
FROM token_transfers tt
JOIN tokens tk
ON tk.chain_id = tt.chain_id
AND tk.token_address = tt.token_address;
La unión por chain_id y la dirección del contrato selecciona el valor decimals correcto para cada token en cada cadena. La conversión de tipo falla con valores de más de 38 dígitos, lo que permite detectar tokens de spam con cantidades en circulación absurdas en lugar de corromper los totales silenciosamente; algunos motores ofrecen en su lugar decimales de 76 dígitos o tipos nativos de 256 bits. POWER devuelve un número de punto flotante en la mayoría de los motores, por lo que amount_display es una aproximación, aceptable solo para la visualización; las sumas y conciliaciones usan amount_raw. No divida por un DECIMAL(38, 0) como alternativa: algunos motores asignan al resultado la escala de los operandos, cero en este caso, y lo truncan silenciosamente a un número entero.
Tiempo: UTC y hora del bloque
Las marcas de tiempo de los bloques son tiempo Unix: segundos transcurridos desde el 1 de enero de 1970, UTC. Mantenga todas las marcas de tiempo en UTC, agrupe los días y meses en UTC e indíquelo en el informe. La conversión a una zona horaria local desplaza las transacciones de un día a otro, y los cambios de horario de verano crean horas que se repiten o que no existen. Una transacción minada a las 23:30 UTC del 31 de marzo pertenece a marzo en un informe en UTC, pero al 1 de abril para un analista cuyas herramientas muestran UTC+2 sin indicarlo; si dos equipos comparan totales mensuales elaborados de ese modo, obtendrán resultados distintos sin que ninguno advierta el motivo. Almacene las marcas de tiempo como valores UTC (o segundos Unix sin procesar) y conviértalas solo en la capa de presentación, indicando la zona utilizada.
Recuerde qué significa la marca de tiempo. Es la hora del bloque, no el momento de la firma o de la difusión, y en Bitcoin puede ser anterior a la del bloque previo. Ordene los eventos por altura (y por posición dentro del bloque), no por marca de tiempo. Al correlacionar actividad entre cadenas, tenga en cuenta las diferencias en los intervalos entre bloques y las reglas de las marcas de tiempo.
Identificadores y sus formatos
Un mismo identificador puede escribirse de varias maneras, y las uniones fallan silenciosamente cuando los formatos difieren.
- Las direcciones EVM aparecen en billeteras y exploradores en el formato de suma de verificación EIP-55, que combina mayúsculas y minúsculas (
0xA1b2…9F), pero en minúsculas en los registros y en la mayoría de los conjuntos de datos. Convierta a minúsculas todas las direcciones y hashes hexadecimales para almacenarlos y realizar uniones; conserve el formato con suma de verificación solo para la visualización. - Valores con relleno: una dirección en un tema de registro ocupa 32 bytes; la dirección corresponde a los últimos 20.
- Los txids de Bitcoin se muestran en el orden inverso al de sus bytes internos; almacene el formato de visualización.
- Direcciones de Bitcoin: las direcciones bech32 y bech32m (
bc1…) no distinguen entre mayúsculas y minúsculas y, por convención, se escriben en minúsculas, pero las direcciones Base58 (1…,3…) sí las distinguen. Convertir una dirección Base58 a minúsculas la destruye. - Las cantidades hexadecimales de JSON-RPC de Ethereum (
"0x1406f52") deben analizarse como base 16; leerlas como cadenas decimales o eliminar el prefijo produce resultados sin sentido.
Identificadores de cadena
La misma dirección puede existir en decenas de cadenas EVM, controlada por la misma clave, pero con saldos independientes, y los hashes de transacción tienen el mismo formato en todas ellas. Cada fila necesita un identificador de cadena. Las cadenas EVM usan el ID de cadena introducido por EIP-155 para proteger contra la reproducción de transacciones y devuelto por eth_chainId:
| Cadena | ID de cadena |
|---|---|
| Red principal de Ethereum | 1 |
| OP Mainnet | 10 |
| BNB Smart Chain | 56 |
| Gnosis | 100 |
| Polygon PoS | 137 |
| Base | 8453 |
| Arbitrum One | 42161 |
| Avalanche C-Chain | 43114 |
| Sepolia (red de pruebas) | 11155111 |
Un registro de ID de cadena mantenido por la comunidad es la referencia habitual para las demás. Use eth_chainId en lugar de net_version, cuyo ID de red puede diferir del ID de cadena. Excluya explícitamente las redes de pruebas y trate los tokens transferidos mediante puentes como activos distintos, con sus propias direcciones de contrato en cada cadena; la lección Puentes, capas 2, cadenas laterales y otros diseños de cadenas aborda el mapeo de los flujos entre ellas. Bitcoin no tiene ID de cadena, pero sus redes de pruebas usan prefijos de dirección diferentes (tb1… en lugar de bc1…).
Deduplicación y claves naturales
Los duplicados se introducen mediante cargas históricas superpuestas, solicitudes reintentadas, reorganizaciones (la misma transacción registrada en dos bloques) y exportaciones fusionadas. Definir una clave natural para cada tipo de registro permite detectarlos:
| Registro | Clave natural |
|---|---|
| Bloque | block_hash |
| Transacción de Bitcoin | block_hash, txid |
| Salida de Bitcoin | txid, vout |
| Transacción EVM | chain_id, hash |
| Registro EVM | chain_id, block_hash, log_index |
| Traza EVM | chain_id, transaction_hash, trace_address |
¿Por qué necesita una transacción de Bitcoin el hash del bloque? Porque no se garantiza que los txids sean únicos: dos transacciones coinbase tempranas se repitieron exactamente en los bloques 91.842 y 91.880, que BIP 30 admitió como excepciones preexistentes y que BIP 34 posteriormente hizo imposibles al exigir la altura del bloque en cada coinbase. La consulta siguiente conserva una copia de cada registro y solo los registros de bloques canónicos:
-- Una fila por registro, solo de bloques canónicos
WITH ranked AS (
SELECT l.*,
ROW_NUMBER() OVER (
PARTITION BY l.chain_id, l.block_hash, l.log_index
ORDER BY l.ingested_at DESC) AS rn
FROM raw_logs l
)
SELECT *
FROM ranked
WHERE rn = 1
AND block_hash IN (SELECT block_hash FROM canonical_blocks);
ROW_NUMBER numera las copias de cada clave y conserva la incorporada más recientemente; el filtro final elimina los registros de bloques que una reorganización sustituyó. Los duplicados lógicos también importan: contar un registro Transfer y la traza de la misma llamada al token, o ETH nativo junto con WETH, contabiliza el valor dos veces.
Registro de la procedencia
La procedencia es el registro de dónde proviene un conjunto de datos y cómo se elaboró. Adjunte uno a cada extracción que sustente un hallazgo:
{
"dataset": "token_transfers_to_target",
"chain_id": 1,
"block_range": [21000000, 21000999],
"anchor_block_hash": "0x5e1c…a7d0",
"finality": "finalized",
"source": "own archive node",
"client_version": "Geth/v1.16.x",
"method": "eth_getLogs",
"query_file": "queries/transfers_to_target.sql",
"retrieved_at_utc": "2026-10-28T14:05:00Z",
"row_count": 37,
"output_sha256": "b94d…e9f1"
}
El rango de bloques y el hash de anclaje fijan los datos; el estado de finalidad muestra que no pueden cambiar; la fuente, la versión del cliente y el método identifican cómo se obtuvieron; el archivo de consulta registra la transformación; la hora de obtención en UTC los fecha; y el número de filas y el hash SHA-256 del archivo de salida permiten a cualquiera confirmar que dispone de los mismos datos. Un revisor con un nodo puede volver a ejecutar la consulta y comparar los resultados. La lección Herramientas, reproducibilidad y validación amplía este enfoque a las consultas versionadas en un almacén de datos.
Errores de datos comunes
| Error | Síntoma | Prevención |
|---|---|---|
| Importes de punto flotante | Desviaciones en los últimos dígitos de los totales | Unidades base enteras, análisis decimal |
| Decimales incorrectos | Importes desviados por 10^12 (6 tratados como 18) | Leer decimals por contrato y cadena |
| Zona horaria local | Totales diarios desplazados entre días | UTC en todo el proceso |
| Falta de ID de cadena | Actividad de una cadena lateral incluida en los totales de la red principal | chain_id en cada fila y unión |
| Transacciones fallidas contabilizadas | Valor que nunca se movió | Filtrar por status = 1 y por errores en las trazas |
| Filas de bloques sustituidos por reorganizaciones conservadas | Transacciones ausentes de la cadena final | Unir con los bloques canónicos por hash |
| Identificadores alterados por cambios de mayúsculas y minúsculas | Las uniones omiten filas; direcciones Base58 dañadas | Convertir a minúsculas solo los valores hexadecimales |
Una comprobación final de bajo costo detecta muchos de estos errores a la vez: seleccione entre tres y cinco filas que sean las más importantes para un hallazgo y verifique cada una con un nodo o una segunda fuente, comparando el hash del bloque, el importe en unidades base y la marca de tiempo. Si una sola fila no coincide, deténgase y averigüe por qué antes de confiar en el agregado.
Enfoque del examen: satoshi, wei, gwei y decimales de los tokens, y por qué los importes se mantienen como enteros; riesgos del punto flotante y del desbordamiento de 64 bits (BIGINT solo admite unos 9,22 ETH en wei); marcas de tiempo UTC y ordenación por altura; sumas de verificación EIP-55 frente al almacenamiento en minúsculas y la distinción entre mayúsculas y minúsculas de Base58; ID de cadena (EIP-155, eth_chainId) y por qué cada fila necesita uno; claves naturales para la deduplicación y los txids duplicados de BIP 30; los campos de un registro de procedencia; los errores de datos comunes y cómo evitarlos.Preguntas de práctica
Comprueba lo que has aprendido. Estas preguntas no cuentan para el examen.
Inicia sesión para guardar tu progreso y continuar donde lo dejaste. Es gratis. Iniciar sesión