Lectura de datos sin procesar de la cadena de bloques · Lección 3 de 6
Transacciones sin procesar de Bitcoin
10 min de lectura
Los exploradores muestran una transacción de Bitcoin como listas ordenadas de direcciones y montos, pero esa vista es una decodificación de bytes sin procesar, y parte de lo que muestra no está en la transacción en absoluto. Leer la estructura sin procesar permite saber qué se registra en la cadena y qué se derivó, por qué la comisión no se puede calcular a partir de una transacción por sí sola y qué campos contienen las huellas en las que se basan heurísticas posteriores.
La serialización, campo por campo
Una transacción se transmite y almacena como una cadena de bytes. Desde SegWit (BIP 141, activado en agosto de 2017), hay dos formas: la forma heredada y la forma extendida definida en BIP 144, que se usa cuando al menos una entrada contiene datos de testigo.
| Campo | Tamaño | Notas |
|---|---|---|
| versión | 4 bytes | Entero little-endian, normalmente 1 o 2 |
| marcador, indicador | 2 bytes | 00 01, presente solo en la forma SegWit |
| cantidad de entradas | variable | Entero CompactSize |
| entradas | variable | Cada una: txid anterior (32), índice de salida (4), longitud de scriptSig y scriptSig, secuencia (4) |
| cantidad de salidas | variable | Entero CompactSize |
| salidas | variable | Cada una: valor en satoshis (8), longitud de scriptPubKey y scriptPubKey |
| testigo | variable | Solo en la forma SegWit: para cada entrada, una cantidad de elementos y los elementos |
| locktime | 4 bytes | Altura de bloque o tiempo más tempranos en que la transacción es válida |
Los enteros son little-endian: primero aparece el byte menos significativo. Un entero CompactSize ocupa un byte para valores inferiores a 253; para los demás, lleva un byte de prefijo (fd, fe o ff) seguido de 2, 4 u 8 bytes. A continuación se muestra una transacción SegWit con una entrada y dos salidas, dividida en sus campos y con los valores largos truncados:
02000000 versión 2
00 01 marcador e indicador SegWit
01 cantidad de entradas 1
ab09…1d7c txid anterior, orden interno de bytes (32 bytes)
01000000 índice de salida anterior 1
00 longitud de scriptSig 0 (entrada SegWit nativa)
fdffffff secuencia 0xfffffffd
02 cantidad de salidas 2
40420f0000000000 valor 1.000.000 sat
16 0014 3c1e…9d02 script, 22 bytes: P2WPKH
0c6a070000000000 valor 485.900 sat
16 0014 77b4…e051 script, 22 bytes: P2WPKH
02 47 3044…01 21 02a1…5f testigo: 2 elementos, firma (71 bytes), clave pública (33 bytes)
00000000 locktime 0
Lee el primer valor invirtiendo sus bytes: 40 42 0f 00 … se convierte en 0x0f4240, que equivale a 1.000.000 satoshis (0,01 BTC). Observa qué falta: no hay dirección del remitente, monto de entrada ni comisión.
Entradas y outpoints
Una entrada no contiene monedas; apunta a una salida anterior, llamada outpoint, escrita txid:vout. El txid de 32 bytes dentro de la entrada se almacena en orden interno de bytes, inverso al orden en que lo muestran los exploradores: ab09…1d7c en los bytes es 7c1d…09ab en pantalla. Olvidar esta inversión es una causa clásica del error «transacción no encontrada».
El monto y el script que se gasta están en la salida anterior, no en la entrada. Para saber quién pagó y cuánto, debes consultar cada outpoint. El scriptSig de la entrada (para scripts heredados) o su testigo (para scripts SegWit) proporciona los datos que satisfacen las condiciones de la salida anterior, normalmente firmas y claves públicas.
El campo sequence de 4 bytes también indica una intención: los valores inferiores a 0xfffffffe señalan que la transacción puede reemplazarse según BIP 125 y, como 0xfffffffd es la opción habitual, también sirven como huella de la billetera. Desde Bitcoin Core 28.0 (2024), los nodos aceptan reemplazos de manera predeterminada, tanto si la transacción original lo indicó como si no; por eso, hoy el valor les importa a los analistas principalmente como huella. Los bloqueos temporales relativos (BIP 68) usan el mismo campo. Una entrada coinbase, que crea monedas nuevas, tiene un txid anterior compuesto por ceros y el índice 0xffffffff.
Versión, locktime y huellas de billetera
Los campos alrededor de las entradas y salidas parecen datos estándar, pero contienen información. La versión es 1 o 2 en casi todas las transacciones; la versión 2 es necesaria para los bloqueos temporales relativos, y las billeteras varían en cuál usan. El locktime se interpreta como una altura de bloque si es inferior a 500.000.000 y como una marca de tiempo Unix en caso contrario; cero significa que no hay restricciones. Muchas billeteras lo fijan en la altura del bloque actual para disuadir a los mineros de reescribir bloques recientes con el fin de capturar comisiones (una práctica llamada protección contra el fee sniping). Por eso, un locktime de 880.213 en una transacción confirmada en 880.214 dice algo sobre el software que la creó.
Los valores de versión, locktime y sequence, junto con los tipos de script utilizados y el orden de las salidas, forman una huella de billetera. Una sola huella no demuestra nada, pero una combinación coherente entre transacciones es una de las señales que usa la lección Heurísticas para detectar el cambio para distinguir un pago del cambio.
Salidas y tipos de script
Cada salida contiene un valor en satoshis y un scriptPubKey, la condición para gastarla. Los scripts estándar siguen plantillas fijas, así que el tipo se puede identificar a partir de los primeros bytes:
| Tipo | Patrón de scriptPubKey | Longitud | Definido en | Las direcciones comienzan con | type de Bitcoin Core |
|---|---|---|---|---|---|
| P2PKH | 76 a9 14 {20 bytes} 88 ac | 25 | original | 1 | pubkeyhash |
| P2SH | a9 14 {20 bytes} 87 | 23 | BIP 16 | 3 | scripthash |
| P2WPKH | 00 14 {20 bytes} | 22 | BIP 141 | bc1q | witness_v0_keyhash |
| P2WSH | 00 20 {32 bytes} | 34 | BIP 141 | bc1q (más larga) | witness_v0_scripthash |
| P2TR | 51 20 {32 bytes} | 34 | BIP 341 | bc1p | witness_v1_taproot |
| OP_RETURN | 6a … | variable | — | ninguna | nulldata |
En P2PKH, 76 a9 14 … 88 ac corresponde a OP_DUP OP_HASH160 {push 20 bytes} OP_EQUALVERIFY OP_CHECKSIG. Las salidas SegWit comienzan con un código de operación de versión (00 para la versión 0, 51 para la versión 1, Taproot) seguido de una inserción del programa. Una salida OP_RETURN es demostrablemente imposible de gastar y contiene datos, no valor.
Una dirección es una codificación de un script estándar, no un campo de la transacción. Los decodificadores la derivan; en el caso de un script no estándar, puede que no haya ninguna dirección, y los exploradores podrían mostrar algo improvisado. Las codificaciones se explican en la lección Tipos de script y formatos de dirección.
Datos de testigo
SegWit mueve las firmas fuera del scriptSig, a una sección de testigo separada. Lo que contiene el testigo depende del tipo que se gasta:
- P2WPKH: dos elementos, una firma DER con un byte sighash (normalmente de 71 o 72 bytes) y una clave pública comprimida de 33 bytes.
- P2WSH: los elementos que satisfacen las condiciones, seguidos del script de testigo en sí, por ejemplo, un script multifirma 2 de 3. La política de gasto solo se hace visible cuando se gasta la salida.
- Ruta de clave P2TR: una única firma Schnorr de 64 bytes (BIP 340), o de 65 bytes con un tipo sighash no predeterminado. En un gasto por ruta de script, en cambio, se revela un script (BIP 342) y un bloque de control.
- SegWit envuelto en P2SH: el scriptSig solo contiene un script de canje corto, como
0014…, y las firmas están en el testigo.
Los bytes de testigo tienen un costo reducido en el espacio del bloque. BIP 141 define el peso como tamaño base × 3 + tamaño total, donde el tamaño base excluye el marcador, el indicador y el testigo. El tamaño virtual (vsize) es el peso ÷ 4, redondeado hacia arriba, y las tasas de comisión se cotizan por vbyte.
Una transacción decodificada en JSON
getrawtransaction de Bitcoin Core, con verbosity 2, devuelve la transacción anterior decodificada, además de cada salida gastada (prevout) y la comisión, si el nodo tiene los datos de deshacer del bloque:
{
"txid": "4f3a…c21e", "hash": "9b07…e4d2",
"version": 2, "size": 222, "vsize": 141, "weight": 561, "locktime": 0,
"vin": [{
"txid": "7c1d…09ab", "vout": 1,
"scriptSig": {"asm": "", "hex": ""},
"txinwitness": ["3044…01", "02a1…5f"],
"prevout": {"value": 0.01500000, "height": 868120,
"scriptPubKey": {"type": "witness_v0_keyhash", "address": "bc1q…7k3f"}},
"sequence": 4294967293
}],
"vout": [
{"value": 0.01000000, "n": 0,
"scriptPubKey": {"type": "witness_v0_keyhash", "address": "bc1q…m2d8"}},
{"value": 0.00485900, "n": 1,
"scriptPubKey": {"type": "witness_v0_keyhash", "address": "bc1q…x9qa"}}
],
"fee": 0.00014100
}
Los tamaños coinciden: la forma base ocupa 113 bytes y la sección de testigo, contando el marcador y el indicador, agrega 109, para un total de 222 bytes. El peso es 113 × 3 + 222 = 561, y 561 ÷ 4 se redondea hacia arriba a un vsize de 141. Los montos están expresados en BTC como números JSON; conviértelos a satoshis enteros antes de hacer cualquier cálculo, como se explica en la lección Calidad, normalización y procedencia de los datos. decoderawtransaction sin más devuelve la misma estructura, pero sin prevout ni fee, porque no tiene acceso a las salidas anteriores.
Calcular la comisión a partir de datos sin procesar
La comisión nunca se indica en la transacción. Es la diferencia entre el valor de las entradas y el de las salidas:
- Entradas: un outpoint con un valor de 1.500.000 sat
- Salidas: 1.000.000 + 485.900 = 1.485.900 sat
- Comisión: 1.500.000 − 1.485.900 = 14.100 sat; por lo tanto, 14.100 ÷ 141 = 100 sat/vB
Una transacción coinbase no tiene comisión; sus salidas reclaman el subsidio del bloque más las comisiones de todas las demás transacciones. En un almacén de datos con tablas separadas para entradas y salidas, el mismo cálculo se ve así (los nombres de las tablas y columnas varían según el conjunto de datos):
-- Comisión por transacción en satoshis: suma de las salidas gastadas menos suma de las salidas nuevas
WITH ins AS (
SELECT i.spending_txid AS txid, SUM(o.value_sat) AS in_sat
FROM inputs i
JOIN outputs o ON o.txid = i.prev_txid AND o.vout = i.prev_vout
GROUP BY i.spending_txid
), outs AS (
SELECT txid, SUM(value_sat) AS out_sat FROM outputs GROUP BY txid
)
SELECT ins.txid, ins.in_sat - outs.out_sat AS fee_sat
FROM ins JOIN outs ON outs.txid = ins.txid;
La unión de cada entrada con su salida anterior es el paso que la transacción sin procesar no puede realizar por sí sola. Las transacciones coinbase quedan excluidas porque sus entradas no coinciden con ninguna salida anterior.
txid frente a wtxid
El txid es el doble SHA-256 de la transacción serializada sin el marcador, el indicador ni el testigo. El wtxid es el mismo hash aplicado a la forma SegWit completa. En una transacción sin datos de testigo, ambos son idénticos; Bitcoin Core muestra el wtxid como hash.
Excluir el testigo del txid resolvió un problema de larga data: la maleabilidad por terceros. Alterar la codificación de una firma solía cambiar el txid de una transacción que, por lo demás, era idéntica. Los cambios en el testigo solo modifican el wtxid, de modo que las cadenas de transacciones no confirmadas pueden referenciarse entre sí de forma segura. Los bloques se comprometen con los wtxid mediante un compromiso de testigo en la transacción coinbase, donde el wtxid de la propia coinbase cuenta como cero. En informes y búsquedas, identifica las transacciones por su txid en el orden de bytes que se muestra.
Enfoque del examen: el orden y el tamaño de los campos de serialización, los enteros little-endian y CompactSize; los outpoints y el orden interno de bytes invertido de los txid; las plantillas de scriptPubKey de P2PKH, P2SH, P2WPKH, P2WSH y P2TR, con sus BIP y prefijos de dirección; que las direcciones se derivan, no se almacenan; qué revelan los testigos para cada tipo de script; el peso (base × 3 + total) y el vsize; cómo calcular la comisión a partir de las salidas anteriores; txid frente a wtxid y maleabilidad.