That is one technique to parse a bitcoin transaction manually, one degree above the script degree.
This tutorial follows the teachings taught by Base58 Bitcoin Developer Fundamentals: Transactions, Scripts + SegWit
To parse a Bitcoin transaction, it’s a pre-requisite to know encoding, decoding, and endianess. Therefore, this evaluation will assume the data of calculating a hex coded quantity again to integer, and a sequence of bytes organized from little endian to large endian.
Here’s a high-level illustration of the sphere sorts in a Bitcoin transaction.

First Ever Bitcoin Transaction: Satoshi Nakamoto Despatched Hal Finney 10 BTC
You’ll be able to lookup the transaction on blockstream.information utilizing the txid under.
txid = ‘f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16’
In case you are utilizing Bitcoin Core, you’ll be able to go the txid as a parameter and fetch the raw_hex, or uncooked transaction information, utilizing this command:
bitcoin-cli getrawtransaction f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16
I added areas in between fields of the raw_hex as type of pre-parsing, however under I clarify step-by-step what every subject means and easy methods to decode them.
raw_hex = ‘01000000 01 c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 00000000 48 47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 ffffffff 02 00ca9a3b00000000 43 4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac 00286bee00000000 43 410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac 00000000’
Decoding Every Area
Model
The primary subject within the raw_hex is the model quantity that has a mounted size of 4 bytes. Meaning 8 hexadecimal characters. Fastened-length fields are at all times little endian. They should be transformed to large endian, after which decoded from hex to integer. This Python code will do the conversion for you:
# Python_1 script to decode fixed-length fields to an integer.
worth = int.from_bytes(bytes.fromhex('hex_value_with_quotes'), 'little')
print(worth)
–> Signifies the method of decoding, or the conversion.
“model”, 4 bytes, 8 hex characters: 01000000 –> 1
Rely of Inputs, input_count
The second subject represents the rely of inputs. It has 1-byte and its format is CompactSize.
CompactSize fields have some tough guidelines. First, you may at all times parse the primary byte, 2 hexadecimal characters, and convert from hex to int, straight up.
-
If the worth is lower than 253, you needn’t fear about endianess as a result of the worth is inside a single byte. Simply use the worth you bought from the direct conversion from hex to integer.
-
If the worth is 253, the enter rely would be the subsequent 2 bytes, 4 hexadecimal characters. Do not forget that at this level you MUST convert from little endian to large endian earlier than changing from hex to integer.
-
If the quantity is 254, the enter rely would be the subsequent 4 bytes, 8 hexadecimal characters. Convert from little endian to large endian earlier than changing hex to integer.
-
If the quantity is 255, the enter rely would be the subsequent 8 bytes, 16 hexadecimal characters. Convert from little endian to large endian earlier than changing hex to integer.
“input_count”, 1 byte at first, 2 hex characters: 01 –> 1
Supply Transaction ID, txid
The subsequent step is to parse the tx id supply, or the id of the origin of the enter. Right here, you’ll hold the sphere in hexadecimal. Totally different from different fixed-length fields in a Bitcoin transaction, the tx ids shouldn’t be transformed to integer and must be stored in hex.
Nevertheless, it’s good to convert from little endian to large endian. This subject is at all times 32-bytes, 64 hexadecimal characters.
Since you’ll NOT decode from hex to int, this mounted size hex must be transformed to bytes, then from little endian to large endian, then again to hex.
You will know you parsed accurately if you should use the decoded worth in a block explorer and discover the transaction there.
See under a easy Python script that may do this for you.
# Python_2 script to interrupt down hex to bytes, reorganize from little endian to large endian, then assemble the worth again to hex.
txid_bytes = bytes.fromhex('hex_value_with_quotes')[::-1].hex()
print(txid_bytes)
“txid”, 32 bytes, 64 hex characters: c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704 —> 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9
Vector Output or Output Index, vout
The subsequent subject is the vout, vector output or output index. It’s the index of the output of the earlier transaction that’s getting used as an enter for the present transaction.
Word that it may be fetched solely after we’ve the supply tx id (id of the earlier transaction). The vout has a set size of 4 bytes. You might want to convert the vout from little endian to large endian, then from hex to int. You should use the Python_1 script.
“vout”, 4 bytes, 8 hex characters: 00000000 –> 0
Unlocking Script Size, scriptSig_len
Now we’ve one other CompactSize subject representing the scriptSig size. Relying on the complexity of the spending guidelines, the scriptSig can have a variable variety of hexadecimal characters. The scriptSig_len determines such quantity so we will parse accordingly.
First let’s convert the primary byte from hex to int and see whether it is smaller than 253.
“scriptSig_len”, 1 byte at first, 2 hex characters: 48 –> 72 bytes –> 144 hex characters
Since 72 it’s smaller than 253, let’s rely 144 hexadecimal characters.
Word that the CompactSize in scriptSig_len represents a size in bytes, whereas a CompactSize in input_count represents the pure counting of integers.
Unlocking Script, scriptSig
The subsequent 144 characters are the unlocking script, or scriptSig. This worth is already in large endian and doesn’t require conversion.
“scriptSig”, variable measurement: 4847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901
nSequence
Subsequent is the nSequence, a fixed-length subject of 4-bytes, 8 hexadecimal characters. It’s in little endian and could be transformed to large endian, then from hex to int utilizing that earlier Python_1 script.
The flexibility of the nSequence subject displays the evolving nature of Bitcoin’s protocol and its adaptability to new use instances and enhancements. It performs a vital function in enabling numerous kinds of transaction flexibility, significantly by way of timelocks and transaction alternative insurance policies.
“sequence”, 4 bytes, 8 hex characters: ffffffff –> 4294967295
Rely of Outputs, output_count
Theis subject represents the rely of outputs. You’ll be able to comply with the identical guidelines of decoding used within the rely of inputs. Decode the primary byte and comply with the principles of CompactSize decoding.
“output_count”, 1 byte at first, 2 hex characters: 02 –> 2
Worth in Satoshis, quantity
Now it’s time to calculate the quantity in satoshis of this tx. This worth is a fixed-length with 8 bytes. You should use the Python_1 script.
“quantity”, 8 bytes, 16 hex characters: 00ca9a3b00000000 –> 1000000000
Locking Script Size, scriptPubKey_len
Now comes the script size of the output script, or locking script. Do not forget that it’s a CompactSize that may give the size in bytes. Let’s parse the primary byte from hex to int and see if the variety of bytes is smaller than 253.
“scriptPubKey_len”, 1-byte at first, 2 hex characters : 43 –> 67 bytes –> 134 hex characters
Locking Script, scriptPubKey
The subsequent 134 characters are the locking script, or scriptPubKey. This worth is already in large endian and doesn’t require conversion.
“scriptPubKey”, variable measurement: 4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac
Second Output Worth in Satoshis, quantity
Subsequent, we’ll parse the second quantity worth to satoshis. You should use the Python_1 script.
“quantity”, 8 bytes, 16 hex characters : 00286bee00000000 –> 4000000000
Second Output Locking Script Size, scriptPubKey_len
Now let’s parse the second locking script size, in CompactSize.
“scriptPubKey_len”, 1 byte at first, 2 hex characters : 43 –> 67 bytes –> 134 hex characters
Second Output Locking Script, scriptPubKey
Now, by counting the following 134 hex characters, we’ve the scriptPubkey correct.
“scriptPubKey”, variable measurement: 410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac
nLocktime
The final worth is the locktime. It’s a mounted size subject. Convert it from 4-byte little endian then from hex to an integer. You should use that Python_1 script right here too.
“locktime”, 4 bytes, 8 hex characters: 00000000 –> 0
Parsed-by-Hand tx in a Python dict format
parsed_tx = {
"model": 1,
"input_count": 1,
"inputs": [
{
"txid": '0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9',
"vout": 0,
"scriptSig_len": 72,
"scriptSig": '47304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901',
"sequence": 4294967295,
},
],
"output_count": 2,
"outputs": [
{
"amount": 1000000000,
"scriptPubKey_len": 67,
"scriptPubKey": '4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac'
},
{
"amount": 4000000000,
"scriptPubKey_len": 67,
"scriptPubKey": '410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac'
},
],
"locktime": 0
}
https://github.com/biohazel/tech-writing/blob/grasp/2023-12-15-parsing-btc-tx-by-hand-v0.0.0.md