Every transaction we have studied so far answers the question who can spend. Signatures prove ownership; scripts encode spending conditions; multisig requires agreement among parties. But none of these mechanisms answers an equally important question: when can the funds be spent?
Bitcoin's timelock system answers this question through four complementary mechanisms, organized along two axes:
Absolute timelocks say "not before block \(X\)" or "not before time \(T\)." Relative timelocks say "not until \(n\) blocks (or \(t\) seconds) after the input was confirmed." Transaction-level locks are enforced by nodes checking header fields. Script-level locks are enforced by the Script interpreter during execution.
This chapter examines each mechanism in detail, building from the simplest (nLockTime, present since the Genesis block) to the most sophisticated (OP_CSV, which enables Lightning Network payment channels).
Every transaction has a 4-byte nLockTime field—the very last field in the transaction, in both legacy and SegWit serialization. We have encountered it in every specimen, always as 00 00 00 00—except in Chapter 12, where our Taproot specimen had:
ff d3 0a 00 — nLockTime = 709,631 (little-endian)
This meant the transaction could not be included in any block at height 709,631 or below — the earliest valid block is 709,632.
The nLockTime field has a dual interpretation based on its value:
| Value | Interpretation | Meaning |
|---|---|---|
| \(0\) | Disabled | Transaction valid immediately |
| \(1\)–\(499,999,999\) | Block height | Not valid until block height \(>\) nLockTime (earliest: nLockTime + 1) |
| \(\geq 500,000,000\) | UNIX timestamp | Not valid until time \(\geq\) nLockTime |
The threshold 500,000,000 corresponds to November 5, 1985—well before Bitcoin's creation, ensuring no ambiguity between heights and timestamps for any real transaction.
When a node receives a transaction with \(\texttt{nLockTime} > 0\):
nLockTime alone provides weak guarantees. A transaction with \(\texttt{nLockTime} = 800,000\) cannot be mined before block 800,000—but nothing prevents the sender from creating a second transaction spending the same inputs with \(\texttt{nLockTime} = 0\), broadcasting it immediately, and invalidating the time-locked version. nLockTime constrains when a transaction can be mined, not when the underlying funds can be spent. For enforceable timelocks, you need script-level locks (CLTV or CSV).
There is a critical exception: nLockTime is only enforced if at least one input has \(\texttt{nSequence} < \texttt{0xFFFFFFFF}\). If every input's sequence number is 0xFFFFFFFF (the maximum), nLockTime is ignored entirely and the transaction is valid at any time.
This was Satoshi's original design: nSequence was intended for transaction "replacement"—parties could update a transaction by incrementing the sequence number, with the highest-sequence version being final. Once all sequences reached the maximum, no more updates were possible, and nLockTime became irrelevant.
In practice, this replacement mechanism was never used (it was a denial-of-service vector). But the nSequence/nLockTime interaction remains in consensus and has been repurposed by BIP 68 (relative timelocks) and BIP 125 (Replace-by-Fee).
Modern wallets set nLockTime to the current block height as an anti-fee-sniping measure. Fee sniping is a game-theoretic attack where a miner re-mines a recent block to claim its fees for themselves. By setting nLockTime to the current height, the transaction cannot be included in any earlier block—making fee sniping unprofitable unless an attacker controls overwhelming hashpower.
Suppose block 840,000 has just been mined and contains a single whale consolidation paying a 2 BTC fee—enough that the block is worth 5.125 BTC to its finder (3.125 BTC subsidy + 2 BTC in fees). The mempool available for block 840,001 is thin: 0.2 BTC of aggregate fees.
| Miner strategy | Block built | Reward on success |
|---|---|---|
| Honest: build on tip | 840,001 (new block on top of 840,000) | 3.125 BTC subsidy + 0.2 BTC mempool fees = 3.325 BTC |
| Fee sniper: re-mine the tip | 840,000′ (alternative block at same height, includes the whale tx) | 3.125 BTC subsidy + 2 BTC whale fee = 5.125 BTC |
The sniper's incentive is 1.8 BTC per block—for the same hashing effort—so long as their alternative chain can outpace the honest network long enough to become the longest chain. In a cycle of blocks where one block is much fatter than the next, every new block becomes a potential target.
How nLockTime defeats this. If the whale's wallet set nLockTime = 840,000 when constructing the transaction, the tx is only consensus-valid in block 840,001 or later. A sniper re-mining block 840,000 cannot include the whale tx—it would make the block invalid. The 2 BTC fee is reachable only by miners building forward, destroying the reorg incentive for that specific transaction.
The defense is probabilistic, not absolute: an attacker with overwhelming hashpower could re-mine 840,000 AND 840,001, including the whale tx in their 840,001. But that requires two blocks of wasted work racing the honest network, making the strategy economically unattractive for any miner with less than a clear majority share. Anti-fee-sniping wins by making the attack's expected value negative for every rational minority miner—Bitcoin's usual security posture.
Our Chapter 12 specimen's \(\texttt{nLockTime} = 709,631\) is exactly this: the transaction was created when the chain tip was block 709,631, ensuring it could only be mined in block 709,632 or later. The corresponding \(\texttt{nSequence} = \texttt{0xFFFFFFFD}\) enables both nLockTime enforcement and RBF signaling.
nLockTime constrains the transaction. But what if you want to constrain the output—ensuring that no transaction, regardless of who creates it, can spend the funds before a certain time? This requires a script-level lock.
BIP 65† introduced OP_CHECKLOCKTIMEVERIFY (CLTV, opcode 0xb1)—a Script opcode that verifies the spending transaction's nLockTime against a value on the stack.
A CLTV-locked output uses this script:
<expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG
For example, to lock funds until block 900,000:
03 a0 bb 0d OP_CLTV OP_DROP <pubkey> OP_CHECKSIG
The 03 a0 bb 0d prefix encodes the expiry as a Script push, and it decomposes into two distinct pieces — this is the rule that makes the raw bytes reconcile to 900,000:
03OP_PUSHBYTES_3a0 bb 0d0x0DBBA0 = 900,000The leading 03 is the push opcode, which tells the interpreter "the next 3 bytes are data to push onto the stack." Only the following three bytes encode the number. Reversing them to big-endian gives \(\texttt{0x0DBBA0} = 13 \times 65{,}536 + 187 \times 256 + 160 = 900{,}000\). If you treated all four bytes as the number (little-endian \(\texttt{0x0DBBA003}\) = 230,400,003) it would not reconcile — the 03 is structural, not numeric.
A subtle related rule worth flagging: Script numbers use a sign bit in the high bit of the most-significant byte (the last byte in little-endian). Because 900,000's top byte is 0x0d (high bit clear), no sign-padding is needed. If the value were instead, say, \(\texttt{0x80BBA0}\), the interpreter would read it as negative, so the encoder would append a trailing 00 byte to preserve the positive sign — changing both the byte count and the push opcode (04 instead of 03). The opcode-and-payload are not independent choices; the sign-bit rule forces them to travel together.
The smallest value where the sign-bit rule forces an extra byte is 128 (0x80 → 80 00); the smallest three-byte height where it strikes is 8,388,608 = 223 = 0x800000. Compare its encoding to the 900,000 example:
| Case A: block 900,000 | Case B: block 8,388,608 | |
|---|---|---|
| Big-endian (minimal) | 0d bb a0 | 80 00 00 |
| Naive little-endian | a0 bb 0d | 00 00 80 |
| Top byte (last in LE) | 0x0d = 0000_11012 | 0x80 = 1000_00002 |
| Sign bit | clear → valid positive number | set → interpreter reads as −0, fails CLTV |
| Correction | none needed | append trailing 00 byte |
| Final LE bytes | a0 bb 0d (3 bytes) | 00 00 80 00 (4 bytes) |
| Push opcode | OP_PUSHBYTES_3 = 0x03 | OP_PUSHBYTES_4 = 0x04 |
| Full script push | 03 a0 bb 0d | 04 00 00 80 00 |
Moving from Case A to Case B grows the lock script by exactly one byte — the trailing 00 — and bumps the push opcode by one. Wallet software that builds CLTV scripts has to apply the sign-bit check after computing the naïve minimal encoding; a bug here produces a script whose <expiry> value is interpreted as negative, and CLTV rejects negative lock times outright.
When the Script interpreter encounters OP_CHECKLOCKTIMEVERIFY:
0xFFFFFFFF (ensuring nLockTime is actually enforced).The OP_DROP after CLTV removes the lock-time value from the stack (CLTV doesn't pop it), leaving the stack clean for OP_CHECKSIG.
The locking script is fixed: it requires the spender to prove the lock-time has expired past block 900,000. Pick values for the spending transaction's nLockTime and nSequence, then step through script execution. Each CLTV sub-check lights up ✓ or ✗ independently, so you can see exactly which rule triggered success or failure.
CLTV solves nLockTime's fundamental weakness. Without CLTV, the sender can always bypass nLockTime by creating a competing transaction with \(\texttt{nLockTime} = 0\). With CLTV, the lock is embedded in the output script—the funds literally cannot be spent until the time has passed, regardless of who creates the spending transaction. The lock is on the coins, not the transaction.
The 4-byte nSequence field on each input is the most overloaded field in Bitcoin. It serves three distinct purposes depending on its value:
| Value | Meaning | BIP |
|---|---|---|
0xFFFFFFFF | Final (disables nLockTime) | Original |
0xFFFFFFFE | Final (nLockTime enabled, no RBF) | — |
\(<\) 0xFFFFFFFE, bit 31 set | RBF signal only | BIP 125 |
\(<\) 0xFFFFFFFE, bit 31 clear | Relative timelock + RBF | BIP 68 |
A transaction is considered to signal RBF if any of its inputs carries nSequence \(<\) 0xFFFFFFFE, or if it is a descendant of a transaction that already signals RBF (inherited signaling, BIP 125 Rule 1). Chapter 17 develops this in detail.
When bit 31 is clear (0), the nSequence value encodes a relative timelock per BIP 68†:
| nSequence | Bit 31 (disable) | Bit 22 (type) | Value (bits 0–15) | Meaning |
|---|---|---|---|---|
0x00000001 |
0 · BIP 68 active | 0 · blocks | 1 | 1 block (~10 min) |
0x00000090 |
0 · BIP 68 active | 0 · blocks | 144 | 144 blocks ≈ 1 day |
0x004000A9 |
0 · BIP 68 active | 1 · 512-s units | 169 | 169 × 512 s ≈ 24 h |
0xFFFFFFFF |
1 · BIP 68 disabled | (ignored) | (ignored) | no relative timelock; max sequence (does not signal RBF) |
0xFFFFFFFD |
1 · BIP 68 disabled | (ignored) | (ignored) | RBF signal only (< 0xFFFFFFFE per BIP 125) |
Reading the hex by eye: bit 31 is the high bit of the leftmost hex digit — if that digit is 0–7, bit 31 = 0 (BIP 68 active); if 8–F, bit 31 = 1 (disabled). Bit 22 is the second-highest bit of the third hex digit (which carries bits 23–20) — that digit value is 4, 5, 6, 7, C, D, E, or F when bit 22 is set. Bits 15–0 are the rightmost four hex digits.
0x004000A9To see how a single hex value carries three independent control fields, expand 0x004000A9 bit by bit. Position 0 is bit 31 (leftmost / most significant); position 31 is bit 0 (rightmost / least significant).
Reading left-to-right: BIP 68 is active (bit 31 = 0), the unit is 512-second intervals (bit 22 = 1), and the count is 169. So the input cannot be spent until 169 × 512 ≈ 86,528 seconds ≈ 24 hours after the referenced output was confirmed.
The relative timelock is measured from the block in which the referenced output was confirmed. If the input spends an output confirmed in block 800,000, and nSequence encodes 144 blocks, the spending transaction cannot be mined before block 800,144.
Just as CLTV enforces nLockTime at the script level, OP_CHECKSEQUENCEVERIFY (CSV, opcode 0xb2) enforces BIP 68 relative timelocks at the script level.
BIP 112† allows a script to require that the spending input's nSequence meets a minimum relative delay.
<delay> OP_CHECKSEQUENCEVERIFY OP_DROP <pubkey> OP_CHECKSIG
For example, to require 144 confirmations (\(\approx\)1 day):
02 90 00 OP_CSV OP_DROP <pubkey> OP_CHECKSIG
where 02 90 00 pushes the 2-byte little-endian encoding of 144 (\(= \texttt{0x0090}\)).
When the Script interpreter encounters OP_CHECKSEQUENCEVERIFY:
version \(\geq\) 2 (BIP 68 only enforces relative locks on v2+ transactions).nSequence has bit 31 clear (BIP 68 must be enabled for this input).nSequence must agree (both block-based, or both time-based at 512-second granularity).nSequence \(\geq\) the lower 16 bits of the stack value.The OP_DROP after CSV removes the lock-time value from the stack (CSV doesn't pop it), leaving the stack clean for OP_CHECKSIG.
The locking script is fixed: it requires 144 blocks of confirmation (~24 hours) before the output can be spent. Pick values for the spending transaction's version and the input's nSequence, then step through script execution. Each CSV sub-check lights up ✓ or ✗ independently so you can see exactly which BIP 68/112 rule triggered success or failure.
0x00000090, type-bit clear)
CSV is the critical building block for the Lightning Network. In a Lightning commitment transaction, the to_local output (the channel partner's own funds) is locked with a CSV delay—typically 144 blocks (1 day) to 2,016 blocks (2 weeks). This delay gives the counterparty time to detect a revoked commitment and broadcast a penalty transaction. Without CSV, Lightning's security model would not work.
The distinction between absolute and relative timelocks is fundamental:
| CLTV (Absolute) | CSV (Relative) | |
|---|---|---|
| Question | "After what block/time?" | "How long after confirmation?" |
| Reference | Global (block height or UTC) | Local (confirmation of the input) |
| Script opcode | OP_CHECKLOCKTIMEVERIFY (0xb1) | OP_CHECKSEQUENCEVERIFY (0xb2) |
| Tx field | nLockTime | nSequence |
| Activation | Block 388,381 (Dec 2015) | Block 419,328 (Jul 2016) |
| BIP | 65 | 68, 112, 113 |
| Use case | HODL, escrow timeout | Lightning, vault recovery |
CLTV answers: "These coins cannot be spent before January 1, 2030." CSV answers: "These coins cannot be spent until 144 blocks after they were confirmed." Both can appear in the same script—enabling complex conditions like "Alice can spend after 1,000 blocks from confirmation, OR Bob can spend after January 2030."
The most powerful timelock pattern combines hash locks with time locks, creating a Hash Time-Locked Contract (HTLC):
OP_IF
OP_HASH160 <hash> OP_EQUALVERIFY <recipient_pubkey> OP_CHECKSIG
OP_ELSE
<timeout> OP_CHECKLOCKTIMEVERIFY OP_DROP <sender_pubkey> OP_CHECKSIG
OP_ENDIF
This script has two spending paths:
HTLCs are the atomic building block of the Lightning Network (Chapter 18). They enable trustless multi-hop payments: each hop in a Lightning payment is secured by an HTLC that ensures either the payment completes across all hops, or every participant gets refunded.
Timelocks are about when funds can move. Chapter 17 explores how transactions compete: Replace-by-Fee (RBF) and Child-Pays-for-Parent (CPFP)—the tools for navigating Bitcoin's fee market. Both rely on nSequence, the same field we studied here.
OP_DROP always follow OP_CHECKLOCKTIMEVERIFY in practice?to_local output uses CSV with a 144-block delay. Explain why this delay is necessary for security. What attack does it prevent?OP_IF/OP_ELSE with CLTV.0xFFFFFFFE as a signal. How does RBF signaling interact with BIP 68 relative timelocks? Can a transaction signal RBF and enforce a relative timelock simultaneously?L1. nLockTime values \(< 500,000,000\) are interpreted as block heights: the transaction is invalid before that block. Values \(\geq 500,000,000\) are interpreted as UNIX timestamps: the transaction is invalid before that time. The threshold is \(500,000,000\) (corresponding to November 5, 1985—well before Bitcoin's creation).
L2. If every input has \(\texttt{nSequence} = \texttt{0xFFFFFFFF}\), nLockTime is disabled: the transaction is valid immediately regardless of the nLockTime value. This is the original behavior from Satoshi's design.
L3. OP_CHECKLOCKTIMEVERIFY (CLTV) = 0xb1. OP_CHECKSEQUENCEVERIFY (CSV) = 0xb2.
L4. Because CLTV does not pop the lock-time value from the stack—it only reads it. The value would remain on the stack and interfere with subsequent opcodes (like OP_CHECKSIG). OP_DROP removes it, leaving the stack clean.
L5. Bit 22 is the type flag: if clear (0), the value in bits 0–15 represents blocks; if set (1), the value represents time in 512-second units.
H1. \(900,000 = \texttt{0x0DBBA0}\). In 4-byte little-endian: a0 bb 0d 00.
H2. \(1,008\) blocks, block-based (bit 22 = 0): nSequence = \(1,008 = \texttt{0x03F0}\). Full 4-byte value: 0x000003F0. In little-endian bytes: f0 03 00 00. Bit 31 must be 0 (BIP 68 enabled).
H3. 48 hours = \(48 \times 3,600 = 172,800\) seconds. Each unit = 512 seconds: \(172,800 / 512 = 337.5\), round to 338 units. Time-based: set bit 22. nSequence = \((1 \ll 22) \,|\, 338 = \texttt{0x00400152}\). Verify: \(338 \times 512 = 173,056\) seconds \(= 48.07\) hours.
H4. \(\texttt{nSequence} = \texttt{0xFFFFFFFD}\):
Summary: nLockTime active, RBF active, no relative timelock.
P1. Suppose Alice creates a transaction paying Bob with \(\texttt{nLockTime} = 850,000\) (block 850,000 is one month away). Before block 850,000, Alice can create a new transaction spending the same inputs with \(\texttt{nLockTime} = 0\), broadcast it, and get it mined immediately. Bob's time-locked transaction becomes invalid (double-spend).
CLTV prevents this by embedding the lock in the output script. If Alice locks funds in a CLTV output, any spending transaction must have \(\texttt{nLockTime} \geq 850,000\). Alice cannot create a bypassing transaction because the script itself rejects it. The lock is on the coins, not the transaction.
P2. CLTV compares its stack value against nLockTime, and both must use the same type (heights or timestamps). If the script specifies block 900,000 (a height) but the transaction sets nLockTime to a UNIX timestamp, the comparison is meaningless—900,000 as a timestamp is January 11, 1970, which is always in the past. A malicious spender could bypass the intended lock by using the wrong type. BIP 65 prevents this: if the types don't match, the script fails immediately.
P3. In Lightning, each commitment transaction gives one party their funds immediately (the to_remote output) and the other party their funds after a CSV delay (the to_local output). The delay exists so that if a party broadcasts a revoked commitment (an old state that has been superseded), the counterparty has time to detect it and broadcast a penalty transaction that claims all funds. Without the delay, the cheating party could broadcast an old commitment and immediately spend their output, leaving no window for the penalty. The 144-block (1 day) delay is a security parameter: it must be long enough for the honest party's watchtower to detect the breach and respond.
C1. The 5th halving occurs at block 1,050,000. The CLTV locking script:
03 90 05 10 OP_CLTV OP_DROP <pubkey> OP_CHECKSIG
where 03 90 05 10 pushes the 3-byte little-endian encoding of 1,050,000 (\(= \texttt{0x100590}\)). The spending transaction must have \(\texttt{nLockTime} \geq 1,050,000\) and at least one input with \(\texttt{nSequence} < \texttt{0xFFFFFFFF}\) (to enable nLockTime enforcement).
C2. The two-path escrow script:
OP_IF
OP_2 <alice_pub> <bob_pub> OP_2 OP_CHECKMULTISIG
OP_ELSE
<900000> OP_CHECKLOCKTIMEVERIFY OP_DROP
<alice_pub> OP_CHECKSIG
OP_ENDIF
Path 1 (cooperative): Alice and Bob both sign, supplying OP_TRUE to take the OP_IF branch. No timelock. Path 2 (timeout): After block 900,000, Alice provides her signature with OP_FALSE to take the OP_ELSE branch. The spending transaction must have \(\texttt{nLockTime} \geq 900,000\) and at least one input with \(\texttt{nSequence} < \texttt{0xFFFFFFFF}\). Note: CLTV uses absolute heights. For a relative delay (e.g., "30 days after the output is created"), use CSV instead.
B1. Yes, a transaction can signal RBF and enforce a BIP 68 relative timelock simultaneously. Any nSequence with bit 31 clear and value \(<\) 0xFFFFFFFE satisfies both: bit 31 = 0 activates BIP 68, and the sub-maximum value signals RBF per BIP 125. For example, \(\texttt{nSequence} = \texttt{0x00000090}\) (144-block relative lock) also signals RBF because \(\texttt{0x00000090} < \texttt{0xFFFFFFFE}\).
B2. In a Lightning multi-hop payment, each intermediate node creates an HTLC with two paths: (1) the recipient reveals a hash preimage to claim the funds (the "success" path), or (2) the sender reclaims the funds after a CLTV timeout (the "refund" path). The timeouts decrease along the route: if the payment is A → B → C, the HTLC from A to B might timeout at block \(n+20\), while B to C times out at block \(n+10\). This ensures that if C claims the preimage from B, B has time to claim from A before A's timeout. The hash preimage propagates backward (C → B → A), and the timelocks ensure every hop can claim or refund. The atomicity guarantee: either all hops complete (preimage revealed), or all hops refund (timeouts expire).