Reference Transaction (P2PKH, 1-in/1-out, 191 bytes)
01000000016ce7229f014164e254aad172b1f8b40d496942ad7e323b47e0424c2b2e2e3772010000006a4730440220463fcf8f57a61c4f8ede208773db8732bf
3a0757d929a8cbbe29bf4905fe5ef6022005d74398faf5b24912821836171af44f55f89858f3edf92863cde4823da11d4641210362f5fb9274834bb0cd0376a8
d5d02bdbf459a37a62c5baef3fb06d1159b55597ffffffff01f0991600000000001976a9141f36a49fcf6ada1f74f82377b33b17b68f7a016188acd3740e00
Chunks by protocol
╔═══════╗
║ rawTX ║
╚╤══════╝
├─ version................. 01000000
├─ inputs.................. 01
│ ╔════════╗
├─╢ vin.0 ║
│ ╚╤═══════╝
│ ├─ txid................. 6ce7229f014164e2 54aad172b1f8b40d 496942ad7e323b47 e0424c2b2e2e3772
│ ├─ vout................. 01000000
│ │ ╔══════════════╗
│ ├─╢ scriptSig ║
│ │ ║ length (106) ║...... 6a
│ │ ╚╤═════════════╝
│ │ ├─ OP_PUSH(71)....... 47
│ │ │ └┬───────────────────────────────────────────────────────────────────────────────────
│ │ │ ├─ Signature
│ │ │ │ ↪32 bytes.... 30440220463fcf8f 57a61c4f8ede2087 73db8732bf3a0757 d929a8cbbe29bf49
│ │ │ │ ↪64 bytes.... 05fe5ef6022005d7 4398faf5b2491282 1836171af44f55f8 9858f3edf92863cd
│ │ │ │ ↪70 bytes.... e4823da11d46
│ │ │ ├─ sighash
│ │ │ │ ↪71 bytes.... 41
│ │ │ └───────────────────────────────────────────────────────────────────────────────────
│ │ └─ OP_PUSH(33)....... 21
│ │ └┬───────────────────────────────────────────────────────────────────────────────────
│ │ ├─ Compressed PubKey
│ │ │ ↪32.......... 0362f5fb9274834b b0cd0376a8d5d02b dbf459a37a62c5ba ef3fb06d1159b555
│ │ │ ↪33 bytes.... 97
│ │ └───────────────────────────────────────────────────────────────────────────────────
│ └─ nsequence............ ffffffff
├─ outputs................. 01
│ ╔════════╗
├─╢ vout.0 ║
│ ╚╤═══════╝
│ ├─ amount............... f099160000000000
│ │ ╔══════════════╗
│ └─╢ scriptPubKey ║
│ ║ length (25) ║...... 19
│ ╚╤═════════════╝
│ ├─ OP_DUP............ 76
│ ├─ OP_HASH160........ a9
│ ├─ OP_PUSH20......... 14
│ │ └┬───────────────────────────────────────────────────────────────────────────────────
│ │ ├─ PubKey hash
│ │ │ ↪20 bytes.... 1f36a49fcf6ada1f 74f82377b33b17b6 8f7a0161
│ │ └───────────────────────────────────────────────────────────────────────────────────
│ ├─ OP_EQUALVERIFY.... 88
│ └─ OP_CHECKSIG....... ac
└─ nlocktime............... d3740e00
Processing the TX
TX are predicate scripts — they must evaluate to TRUE (0x01)
- scriptSig execution
- 0x47 pushes 71 bytes (der_sig + sighash) to [1]
- 0x21 pushes 33 bytes (pubkey 🗜️) to [2]
Stack:
[1] 30440220463fcf8f57a61c4f8ede208773db8732bf3a0757d929a8cbbe29bf4905fe5ef6022005d74398faf5b24912821836171af44f55f89858f3edf92863cde4823da11d4641
[2] 0362f5fb9274834bb0cd0376a8d5d02bdbf459a37a62c5baef3fb06d1159b55597
- scriptPubKey execution
- OP_DUP duplicates [2] to [3]
- OP_HASH160 pops [3], hashes it, and pushes it back to [3]
- 0x14 pushes 20 bytes (pubkey #️⃣) to [4]
- OP_EQUALVERIFY pops [4] and [3] and compares them, aborts if not equal
- OP_CHECKSIG pops [2] and [1] pushes TRUE if valid
Stack:
[1] 0x01
The stack now contains TRUE (0x01) therefore the TX is valid.
Byte Offsets
| Offset | Size | Hex | Field |
|---|---|---|---|
| 0 | 4 | 01000000 | version (1) |
| 4 | 1 | 01 | input count (1) |
| 5 | 32 | 6ce7229f...2e2e3772 | prev txid (wire order: wtxid) |
| 37 | 4 | 01000000 | prev vout (1) |
| 41 | 1 | 6a | scriptSig length (106 bytes) |
| 42 | 1 | 47 | . push 71 bytes |
| 43 | 70 | 30440220...da11d46 | . . DER signature |
| 113 | 1 | 41 | . . sighash: FORKID + ALL |
| 114 | 1 | 21 | . push 33 bytes |
| 115 | 33 | 0362f5fb...b55597 | . . compressed pubkey (33 bytes) |
| 148 | 4 | ffffffff | sequence (0xFFFFFFFF) |
| 152 | 1 | 01 | output count (1) |
| 153 | 8 | f099160000000000 | satoshis (1,481,200) |
| 161 | 1 | 19 | scriptPubKey length (25) |
| 162 | 1 | 76 | . OP_DUP |
| 163 | 1 | a9 | . OP_HASH160 |
| 164 | 1 | 14 | . push 20 bytes |
| 165 | 20 | 1f36a49f...7a0161 | . . |
| 185 | 1 | 88 | . OP_EQUALVERIFY |
| 186 | 1 | ac | . OP_CHECKSIG |
| 187 | 4 | d3740e00 | locktime (947,411) |
191 bytes total. Used in test suite as DUMMY_RAW_TX — parseable by Transaction.from_binary and satisfies the tx_proofs.raw_tx >= 20 constraint.
DER signature size distribution
The DER-encoded ECDSA signature uses two integers (r, s), each 32 bytes when fully populated. Leading zeros are stripped, and a sign byte is prepended when the high bit is set. The r and s values are effectively random mod n (≈2^256), so shorter encodings require the value to fall below exponentially smaller thresholds.
| Signature size | Probability | Frequency |
|---|---|---|
| 70–72 bytes | ≈99.8% | Standard |
| 69 bytes | ≈1 in 512 | Uncommon |
| 68 bytes | ≈1 in 131,072 | Rare |
| 60 bytes | ≈1 in 2^80 | Near impossible |
| 8 bytes | ≈1 in 2^496 | Practically impossible |
Each byte below 70 requires the value to be ≈256x smaller. A minimum signed P2PKH transaction (1-in/1-out) is 191 bytes with a typical 70-byte signature, 189 bytes with a 68-byte signature. The database constraint uses 20 bytes (minimum 1-output tx with 1-byte script) because unsigned transactions during deferred signing are ~85 bytes.
PubKey
Pubkey is used twice, in scriptSig where it is compressed and in scriptPubKey where it is hashed
Compressed
When an output is spent the scriptsig must reveal the pubkey so that proof can be verified, to save space the key is compressed.
A public key is a point x,y on a graph. Because the curve is mathematically defined as y^2 = x^3 + 7, if we know x, we can solve the equation to find y. Therefore to save space we just send x.
However y^2 = b has two solutions for b, positive and negative, so the first byte is used to indicate which of these it is 0x02 is even, 0x03 is odd.
Hash
Hashing the pubkey affords privacy to unspent outputs until such time as they need to be spent. The pubkey is hashed using:
ripemd160(sha256(pubkey))
When the output is spent the scriptSig reveals the actual pubkey and this can be hashed to verify it matches the output, which is exactly what the P2PKH script does.
nlocktime
Prevents tx from being mined until a specified time (blockheight or real-time). There are two types of nlocktime, determined by the value.
NB: for nlocktime to be enforced at least one input must have nsequence below 0xffffffff — this applies regardless of which type of nlocktime is used.
0-500,000,000 block height type
Decimal Range 0 to 500,000,000
The transaction cannot be mined until the specified blockheight
Based on the average interval of 10 mins between blocks, it will take ≈9,506 years to reach blockheight 500,000,000.
0x1dcd6500 to 0xffffffff - Unix Time
Decimal Range 500,000,000+
NB: Unix time is implicitly Coordinated Universal Time (UTC).
The transaction cannot be mined until nlocktime seconds after the Unix epoch 00:00:00 on 1 Jan 1970
The earliest possible nlocktime specified this way is 00:53:20 on 5 Nov 1985, well before the first block was mined.
The first block mined at 18:15:05 on 3 Jan 2009 corresponds to the nlocktime 0x495fab29 of (1,231,006,505). The actual nlocktime of this block was zero.
The maximum nlocktime 0xffffffff corresponds to 06:28:15 on 7 Feb 2106
Unix Time, Leap Seconds and Median-Time-Past (MTP)
In unix time, every day is treated as having exactly 86,400 seconds. When a leap second occurs, the Unix clock typically “repeats” a second or steps backward to stay in sync with UTC. It does not increment the counter for that extra second. A Unix timestamp of 500,000,000 represents exactly 500,000,000 ÷ 86,400 days since the Epoch. The leap second system was not introduced until 1 Jan 1972, by which time atomic clocks were already 10 seconds ahead of UTC, and so an initial 10 second offset was applied, and a further 27 leap seconds have been applied since [1]
Practically speaking this additional 37 seconds (in total, as of 3 May 2026) has no effect on Bitcoin nodes. Due to the economic incentives, around mining nodes will converge on using the same Unix-based timestamp and sync their clocks via NTP (Network Time Protocol). Any leap-second drift is therefore already accounted for.
Furthermore nodes rely on the Median-Time-Past (MTP) of the last 11 blocks to determine the “current time” for nLockTime validation.
Consensus on the validity of including a transaction with a unix-time style nlocktime naturally emerges as a confluence of the factors described.