Serialization
Bitcoin protocol objects are byte strings with fixed field order. Unless a field table states otherwise, $E_T$ serializes integers in little-endian byte order, vectors with a CompactSize element count, and byte vectors with a CompactSize byte length followed by exactly that many bytes.
Fixed-width primitives
| Primitive | Width | Serialization rule |
|---|---|---|
uint8 / int8 | 1 byte | Byte value as stored. |
uint16 / int16 | 2 bytes | Least significant byte first. |
uint32 / int32 | 4 bytes | Least significant byte first. |
uint64 / int64 | 8 bytes | Least significant byte first. |
byte[n] | $n$ bytes | Exactly the given bytes, in index order. |
bool | 1 byte | Zero is false; nonzero is true unless a field table restricts the value. |
uint160 | 20 bytes | 160-bit hash value. |
uint256 | 32 bytes | 256-bit hash value. Display hex commonly reverses these bytes. |
Fixed-width integer fields are serialized in little-endian byte order unless a field table explicitly states otherwise (sources: bitcoin-core-v31).
CompactSize
Bitcoin transaction and block structures use CompactSize integers to encode counts and byte-vector lengths. CompactSize is canonical: a decoder rejects a value encoded with a longer form than necessary.
| Value range | Encoding | Canonicality rule |
|---|---|---|
| $0 <= n < 253$ | one byte: $n$ | First byte is less than 0xfd. |
| $253 <= n <= 0xffff$ | 0xfd followed by uint16 | Decoded value must be at least 253. |
| $2^16 <= n <= 2^32-1$ | 0xfe followed by uint32 | Decoded value must be at least 0x10000. |
| $2^32 <= n <= 2^64-1$ | 0xff followed by uint64 | Decoded value must be at least 0x100000000. |
A parser rejects non-canonical CompactSize encodings and any decoded count or length that exceeds the enclosing field’s rule.
Constructors
| Constructor | Serialized form | Used for |
|---|---|---|
vector<T> | `compactSize count | |
varbytes | `compactSize length | |
string | `compactSize length | |
witnessStack | `compactSize itemCount |
Scripts, signatures, public keys, witness items, and network payload fields reuse varbytes in different contexts. Parsing bytes into opcodes, signatures, keys, or scripts is a later semantic step.
For transactions and blocks, $E_0(x)$ is the serialization with witness data stripped, and $E_w(x)$ is the serialization including witness data where such data is defined. Define:
$$ strippedSize(x) = |\mathrm{E}{0}(x)|, \qquad totalSize(x) = |\mathrm{E}{w}(x)|. $$
The consensus weight formula is:
$$ weight(x) = 3 \cdot strippedSize(x) + totalSize(x). $$
For relay and fee accounting, virtual transaction size is the integer ceiling of weight divided by witness scale:
$$ vsize(tx) = \left\lfloor \frac{weight(tx) + \text{\code{WITNESS_SCALE_FACTOR}} - 1} {\text{\code{WITNESS_SCALE_FACTOR}}} \right\rfloor. $$
Block consensus enforces MAX_BLOCK_WEIGHT against weight(block) (sources: bip-0141,bitcoin-core-v31).