This appendix is a quick-reference guide for reading raw Bitcoin transactions byte by byte. Print it, laminate it, and keep it next to your hex editor.
Bitcoin uses a variable-length integer encoding for counts and lengths:
| First Byte | Range | Total Bytes | Encoding |
|---|---|---|---|
0x00–0xfc | 0–252 | 1 | Value is the byte itself |
0xfd | 253–65,535 | 3 | fd + 2 bytes (LE) |
0xfe | 65,536–\(2^{32}-1\) | 5 | fe + 4 bytes (LE) |
0xff | \(2^{32}\)–\(2^{64}-1\) | 9 | ff + 8 bytes (LE) |
| Offset | Size | Field | Notes |
|---|---|---|---|
| 0 | 4 bytes | nVersion | Little-endian. Usually 01000000 (v1) or 02000000 (v2). |
| 4 | varint | vin_count | Number of inputs. |
| +0 | 32 bytes | prev_txid | Internal byte order (reversed from display). |
| +32 | 4 bytes | prev_vout | Output index, little-endian. |
| +36 | varint | scriptSig_len | Length of scriptSig in bytes. |
| +37 | varies | scriptSig | Unlocking script. |
| 4 bytes | nSequence | Usually ffffffff or fdffffff. | |
| varint | vout_count | Number of outputs. | |
| +0 | 8 bytes | value | Satoshis, little-endian. |
| +8 | varint | scriptPubKey_len | Length of scriptPubKey. |
| +9 | varies | scriptPubKey | Locking script. |
| 4 bytes | nLockTime | Little-endian. Block height or Unix time. |
SegWit transactions insert a marker and flag after the version, and append witness data before the locktime:
| Offset | Size | Field | Notes |
|---|---|---|---|
| 0 | 4 bytes | nVersion | Same as legacy. |
| 4 | 1 byte | marker | Always 00. Signals SegWit serialization. |
| 5 | 1 byte | flag | Always 01. |
| 6 | varint | vin_count | Number of inputs. |
| varint | vout_count | Number of outputs. | |
| varint | item_count | Number of witness items for this input. | |
| varint | item_len | Length of witness item. | |
| varies | item_data | Witness item (signature, pubkey, script, etc.). | |
| 4 bytes | nLockTime | Always the last 4 bytes of the raw transaction. |
nVersion, prev_vout, nSequence, value, and nLockTime are all little-endian. The prev_txid is stored in internal byte order (reversed from the display hash shown on block explorers). When you see txid abcd...1234 on mempool.space, the raw bytes are 3412...cdab.
Recognizing the locking script tells you the output type instantly:
| Pattern (hex) | Type | Chapter |
|---|---|---|
41 <65B pubkey> ac | P2PK (uncompressed) | Ch. 4 |
21 <33B pubkey> ac | P2PK (compressed) | Ch. 4 |
76 a9 14 <20B hash> 88 ac | P2PKH | Ch. 5 |
a9 14 <20B hash> 87 | P2SH | Ch. 6 |
00 14 <20B hash> | P2WPKH (native SegWit v0) | Ch. 9 |
00 20 <32B hash> | P2WSH (native SegWit v0) | Ch. 10 |
51 20 <32B key> | P2TR (SegWit v1) | Ch. 12 |
6a <data> | OP_RETURN (unspendable) | Ch. 15 |
51 02 4e73 | P2A (Pay-to-Anchor) | Ch. 17 |
| Bytes | Meaning | Context |
|---|---|---|
01000000 | Version 1 | Pre-BIP 68 transactions |
02000000 | Version 2 | Enables relative timelocks (BIP 68) |
03000000 | Version 3 (TRUC) | BIP 431 transaction relay policy |
0001 | SegWit marker+flag | Immediately after version in SegWit txs |
ffffffff | nSequence max | Disables RBF; disables BIP 68 |
fdffffff | nSequence \(-2\) | RBF signal; BIP 68 disabled |
feffffff | nSequence \(-1\) | RBF signal; BIP 68 disabled |
00000000 | nLockTime 0 | No absolute timelock |
ffffffff… (32 bytes) | Null prevout hash | Coinbase transaction input |
ffffffff (4 bytes) | Coinbase vout index | Always 0xFFFFFFFF for coinbase |
ECDSA signatures in legacy/SegWit v0 use DER encoding:
| Offset | Field | Notes |
|---|---|---|
| 0 | 30 | Compound structure tag |
| 1 | length | Total remaining bytes |
| 2 | 02 | Integer tag for \(r\) |
| 3 | \(r\)-length | Usually 32 or 33 bytes |
| 4 | \(r\)-value | Prepend 00 if high bit set |
02 | Integer tag for \(s\) | |
| \(s\)-length | Usually 32 bytes (low-\(s\) normalized) | |
| \(s\)-value | BIP 146 requires \(s \leq n/2\) | |
| last | sighash byte | 01=ALL, 02=NONE, 03=SINGLE, 81=ANYONECANPAY |
| Value | Name | What It Signs |
|---|---|---|
0x01 | SIGHASH_ALL | All inputs and all outputs (default) |
0x02 | SIGHASH_NONE | All inputs, no outputs |
0x03 | SIGHASH_SINGLE | All inputs, only the output at same index |
0x81 | ALL|ANYONECANPAY | Only this input, all outputs |
0x82 | NONE|ANYONECANPAY | Only this input, no outputs |
0x83 | SINGLE|ANYONECANPAY | Only this input, matching output |
Practice routine: Take any txid from mempool.space, click "Raw Hex," and parse it field by field using this cheat sheet. Start with the version bytes, count the inputs, read each prevout, decode the scriptSig (or note its absence for SegWit), count the outputs, decode each value and scriptPubKey, parse the witness stack if present, and finish with the locktime. After five transactions, you will read hex fluently.
Every byte tells a story. Now you know how to read it.