# Ejemplo para Decodificar una transacción a mano ###### tags: `bitcoin` `cli` `ejercicio` _Ya usaste bitcoin core para ver transacciones, ahora haz una radiografía de como funcionan_ [TOC] ## Autor **EntrePlanctonyBallenas**. Twitter para correcciones, comentarios o sugerencias: [@entreplanctony1](https://twitter.com/Entreplanctony1) El presente ejercicio fue elaborado por **[@niftynei](https://twitter.com/niftynei)**, como parte del curso [Bitcoin Protocol Deep Dive: Transactions ](https://www.udemy.com/course/base58-bitcoin-transactions-one/) en Udemy, si consideras útil este material te sugiero que tomes todo su curso, te será muy útil si quieres adentrarte en el rabbit hole de las transacciones de bitcoin. ## Cheat Sheet de PYTHON :::info 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' :::warning **Valor Hexadecimal de la transacción** 0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000 ::: ### Formulario para identificar los campos de una transacción. :::success 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 ### Aplicamos el formulario y el cheat cheat sobre la transacción :::info **Versión de la transacción** *- 4 bytes - little endian y convertir a Entero* 01000000 **numero de inputs** *- 1 byte - little endian y convertir a Entero* 01 **VINs (vectores de entrada)** **txid** *- 32 bytes - little endian* c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 ``` bytes.fromhex('<CADENA>')[::-1].hex() Resultado: 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9 ``` **vout** *- 4 bytes - little endian y convertir a Entero* 00000000 **scriptsize** *- 1 byte - little endian y convertir a Entero* 48 ``` int(bytes.fromhex('<CADENA>')[::-1].hex(),16) Resultado:72 ``` **scriptsig** *- variable - BIG endian* 47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 **sequence** *- 8 bytes - little endian* ffffffff **VOUTs (Vectores de salida)** **Numero de outputs** *- 1 byte - little endian* 02 **amount** *- 8 bytes - little endian y convertir a Entero* 00ca9a3b00000000 ``` int(bytes.fromhex('<CADENA>')[::-1].hex(),16) Resultado: 10 0000 0000 ``` **scriptsize** *- 1 byte - little endian y convertir a Entero* 43 ``` int(bytes.fromhex('<CADENA>')[::-1].hex(),16) Resultado: 67 ``` **scriptsig** *- variable - BIG endian* 4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac **amount** *- 8 bytes - little endian y convertir a Entero* 00286bee00000000 ``` int(bytes.fromhex('<CADENA>')[::-1].hex(),16) Resultado: 40 0000 0000 ``` **scriptsize** *- 1 byte - little endian y convertir a Entero* 43 ``` int(bytes.fromhex('<CADENA>')[::-1].hex(),16) Resultado: 67 ``` **scriptsig** *- variable - BIG endian* 410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac **LOCKTIME** *- little endian* 00000000 ::: ## 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 Tomamos el mismo formulario, solo queremos saber los valores originales, no nos importa convertir a entero o a Big Endian. Y 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. :::info **Versión de la transacción** 01000000 **segwit marker + flag** 00 01 **numero de inputs** 01 **VINs (vectores de entrada)** **txid** c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 **vout** 00000000 **scriptsize** 00 **sequence** ffffffff **VOUTs (Vectores de salida)** **Numero 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 transaccion Importar librerias 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 ``` ## Como 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 multiplicado 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 = 2 bytes * 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| ::: success 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** :::