Raw Transaction Serialization
How to serialize a Bitcoin transaction into raw hex — version, inputs, outputs, and locktime in the correct byte order.
0steps ·
What You’ll Learn
- The complete serialization format for a Bitcoin transaction
- Little-endian encoding and why Bitcoin uses it
- How to assemble every field into a single hex string
Transaction Format Overview
A serialized Bitcoin transaction is a sequence of bytes with a rigid structure. Here is the layout for a legacy (non-SegWit) transaction:
[Version] [Input Count] [Inputs...] [Output Count] [Outputs...] [Locktime]
For a SegWit transaction, two additional fields are inserted:
[Version] [Marker] [Flag] [Input Count] [Inputs...] [Output Count] [Outputs...] [Witness...] [Locktime]
Let’s walk through each field.
Version (4 bytes)
The transaction version number. Almost all modern transactions use version 2 (which enables relative timelocks via BIP68):
02000000
This is 0x00000002 in little-endian. Version 1 (01000000) is still valid but does not support BIP68 sequence-based timelocks.
Marker and Flag (SegWit only, 2 bytes)
SegWit transactions insert a marker byte (0x00) and a flag byte (0x01) after the version. These tell parsers that witness data follows:
0001
The marker must be 0x00. The flag must be non-zero (currently always 0x01).
Input Count (VarInt)
A variable-length integer indicating the number of inputs. For 1-252 inputs, this is a single byte:
01 → 1 input
02 → 2 inputs
fd → followed by 2-byte little-endian count (for 253+)
Serialized Inputs
Each input is serialized as we described in Step 3:
[Previous TX Hash: 32 bytes]
[Output Index: 4 bytes]
[ScriptSig Length: VarInt]
[ScriptSig: variable]
[Sequence: 4 bytes]
For a SegWit input before signing, the ScriptSig is empty (length = 00).
Output Count (VarInt)
Same encoding as input count. For our 2-output transaction:
02
Serialized Outputs
Each output as described in Step 4:
[Value: 8 bytes]
[ScriptPubKey Length: VarInt]
[ScriptPubKey: variable]
Witness Data (SegWit only)
The witness section appears after all outputs and before the locktime. Each input gets a corresponding witness stack. We will cover this in detail in Step 8, but the structure is:
[Stack item count: VarInt]
[Item 1 length: VarInt] [Item 1 data]
[Item 2 length: VarInt] [Item 2 data]
...
For a P2WPKH input, the witness contains two items: the signature and the public key.
Locktime (4 bytes)
The locktime field specifies the earliest time or block height at which the transaction can be included in a block:
00000000 → No locktime (can be mined immediately)
If the value is below 500,000,000, it is interpreted as a block height. Otherwise, it is a Unix timestamp. Most transactions use 0 or the current block height (to prevent fee sniping — a miner incentive attack).
Little-Endian Encoding
Bitcoin serialization uses little-endian byte order for most multi-byte integers. This means the least significant byte comes first:
Decimal 500,000 = 0x0007A120
Big-endian: 0007A120
Little-endian: 20A10700
The exception is the previous transaction hash, which is stored as a raw 256-bit value — but because txids are traditionally displayed in big-endian, you must reverse the byte order when inserting them into the serialized transaction.
Complete Example
Here is our 1-input, 2-output SegWit transaction (before signing):
02000000 # Version 2
0001 # SegWit marker + flag
01 # 1 input
3f4fa198...7b1eabe0 # Previous TX hash (32 bytes, reversed)
00000000 # Output index 0
00 # Empty ScriptSig
fdffffff # Sequence (RBF enabled)
02 # 2 outputs
e093040000000000 # Output 0: 300,000 sats
160014<recipient-hash> # P2WPKH ScriptPubKey
b882020000000000 # Output 1: 198,590 sats (change)
160014<change-hash> # P2WPKH ScriptPubKey
# Witness data (empty until signing)
00000000 # Locktime 0
This hex blob is not yet valid — it needs a signature. That’s next.
Next Step
Continue to Signing the Transaction to learn how to create the cryptographic proof that authorizes spending.