MASTERING BITCOIN
Tabla de contenidos:

Cómo decodificar transacciones de Bitcoin manualmente. Ejemplo práctico

Ya usaste Bitcoin Core para ver transacciones, ahora haz una radiografía de como funcionan.

Autor

EntrePlanctonyBallenas.
Twitter para correcciones, comentarios o sugerencias: @entreplanctony1

El presente ejercicio fue elaborado por @niftynei, como parte del curso
Bitcoin Protocol Deep Dive: Transactions
en Udemy. Si consideras valioso este material te sugiero que tomes su curso completo, ya que te será mucha utilidad si quieres adentrarte en el rabbit hole de las transacciones de Bitcoin.

Cheat Sheet de PYTHON

Usamos Python desde la línea de comandos para decodificar más rápido. Aquí una lista de comandos que te harán más fácil el ejercicio.

PARA CONVERTIR UN VALOR DE HEXADECIMAL A ENTERO

int('<CADENA>',16)

PARA CONVERTIR UN VALOR HEXADECIMAL A BIG ENDIAN

bytes.fromhex('<CADENA>')[::-1].hex()

PARA CONVERTIR UN VALOR HEXADECIMAL A BIG ENDIAN Y A ENTERO

int(bytes.fromhex('<CADENA>')[::-1].hex(),16)

PARA MEDIR LA LONGITUD DE UNA CADENA HEXADECIMAL EN BYTES

len ('<CADENA>')/2

Ejemplo para Legacy

Tomamos la siguiente transacción:
txid = ‘f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16’

Valor Hexadecimal de la transacción
0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000

Formulario para identificar los campos de una transacción

🛈 Todos los campos de tamaño fijo están codificados en little endian, mientras que los campos que tienen longitud variable usan Big Endian

Versión de la transacción 4 bytes little endian y convertir a entero
Numero de inputs 1 byte little endian y convertir a entero
VINs (vectores de entrada)
txid 32 bytes little endian
vout 4 bytes little endian y convertir a entero
scriptsize 1 byte little endian y convertir a entero
scriptsig variable BIG endian
sequence 8 bytes little endian
VOUTs (vectores de salida)
Numero de outputs 1 byte little endian
amount 8 bytes little endian y convertir a entero
scriptsize 1 byte little endian y convertir a entero
scriptsig variable BIG endian
LOCKTIME 4 bytes little endian
Aplicamos el formulario y el Cheat Sheet sobre la transacción

Ejemplo para SegWit

Diferencias en los campos entre Legacy y SegWit
Legacy Segwit
Versión de la transacción Versión de la transacción
Número de inputs Segwit marker + Flag
Txid Número de inputs
Índice de Vout Txid
Scriptsize Índice de Vout
Scriptsig Scriptsize
Sequence Sequence
Número de outputs Número de outputs
Amount Amount
Scriptsize Scriptsize
ScriptLock ScriptLock
LOCKTIME Witness Stacks
Scriptsig
LOCKTIME
Vamos a convertir la misma transacción Legacy a SegWit

Tomaremos el mismo formulario. Solo queremos saber los valores originales, no nos importa convertir a entero o a Big Endian. Hay que modificar la información tomando en cuenta los campos nuevos. Así mismo, los scripts de desbloqueo se mueven al final de los VOUTs.

Versión de la transacción
01000000
segwit marker + flag
00 01
Número de inputs
01
VINs (vectores de entrada)
txid
c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704
vout
00000000
scriptsize
00
sequence
ffffffff
VOUTs (vectores de salida)

Número de outputs
02
amount
00ca9a3b00000000
scriptsize
43
scriptsig
4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac
amount
00286bee00000000
scriptsize
43
scriptsig
410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac
witness stacks
01
scriptsig
47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901
LOCKTIME
00000000
Resultado:

01000000000101c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd37040000000000ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac0147304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d090100000000

Obtener el txid de una transacción en hexadecimal
Comandos para obtener el hash de una transacción

Importar librerías necesarias:

from hashlib import sha256

Obtenemos los bytes del valor hexadecimal de la transacción:

b = bytes.fromhex('<TXHEX>')

Aplicamos 2 veces el sha256 y volvemos a convertir a hexadecimal y BIG endian:

sha256(sha256(b).digest()).digest()[::-1].hex()

TXID Legacy

Es el hash de toda la información de una transacción

from hashlib import sha256
TXHEX = '0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000'
b = bytes.fromhex(TXHEX)
sha256(sha256(b).digest()).digest()[::-1].hex()

Resultado

f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16

TXID SegWit

Es el hash de toda la información “Legacy de una transacción”. Hay que remover todos los datos hexadecimales que se usen en SegWit.

from hashlib import sha256
TXHEX = '0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd37040000000000ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000'
b = bytes.fromhex(TXHEX)
sha256(sha256(b).digest()).digest()[::-1].hex()
Resultado

f4999544bfc6aad5c629a8eaa015f7df32d3498569073db7f2cebdf4cf13c1e4

Cómo calcular el peso de una transacción
Legacy

El peso de la transacción, se obtiene de la longitud de la transacción en bytes multiplicada por 4. En terminal correr:

len ('<CADENA>')/2 *4
Resultado:
1100
SegWit

El peso de la transacción se calcula de manera distinta, cada campo tiene un peso distinto de acuerdo a su longitud y de acuerdo a si es un campo Legacy (se multiplica la longitud del campo x 4) o SegWit (se multiplica la longitud del campo x 1). Por lo que hay que aplicar los valores como los encontramos en la transacción:

Versión de la transacción 4 bytes * 4 = 16
01000000
Segwit marker + flag 1byte + 1byte = 2bytes * 1 = 2
00 01
Numero de inputs 1 byte * 4 = 4
01
VINs (vectores de entrada)
txid 32 bytes * 4 = 128
c997a5e56e104102fa209c6a852dd90660
a20b2d9c352423edce25857fcd3704
vout 4 bytes * 4 = 16
00000000
scriptsize 1 byte * 4 = 4
00
sequence 4 bytes * 4 = 16
ffffffff
VOUTs (vectores de salida)
Numero de outputs 1 byte * 4 = 4
02
amount 8 bytes * 4 = 32
00ca9a3b00000000
scriptsize 1 byte * 4 = 4
43
scriptsig 67 bytes * 4 = 268
4104ae1a62fe09c5f51b13905f07f06b99a2
f7159b2225f374cd378d71302fa28414e7aa
b37397f554a7df5f142c21c1b7303b8a0626
f1baded5c72a704f7e6cd84cac
amount 8 bytes * 4 = 32
00286bee00000000
scriptsize 1 byte * 4 = 4
43
scriptsig 67 bytes * 4 = 268
410411db93e1dcdb8a016b49840f8c53bc1eb
68a382e97b1482ecad7b148a6909a5cb2e0ea
ddfb84ccf9744464f82e160bfa9b8b64f9d4c
03f999b8643f656b412a3ac
witness stacks 1 byte * 1 = 1
01
scriptsig 72 bytes * 1 = 72
47304402204e45e16932b8af514961a1d3a1a
25fdf3f4f7732e9d624c6c61548ab5fb8cd41
0220181522ec8eca07de4860a4acdd12909d8
31cc56cbbac4622082221a8768d1d0901
LOCKTIME 4 bytes * 4 = 16
00000000
Por lo que el peso de esta transacción SegWit sería: 16 + 2 + 4 + 128 + 16 + 4 + 16 + 4 + 32 + 4 + 268 + 32 + 4 + 268 + 1 + 72 + 16 = 887