Hash Time-Locked Contracts (HTLCs)
HTLCs are the mechanism that enables payments to route through the Lightning Network. They ensure that payments can only be claimed with the correct preimage, and expire after a certain time if unclaimed. An HTLC is a conditional payment that requires:
- Hash Lock: Knowledge of a secret (preimage) that hashes to a known value
- Time Lock: Expires after a certain block height (CLTV)
HTLC Conditions:
- If preimage is revealed before expiry → Payment goes to recipient
- If time lock expires → Payment returns to sender
How HTLCs Work in Lightning
Payment Flow
- Recipient generates preimage: Random 32-byte secret, shares SHA256 hash
- Sender creates HTLC chain: Locks funds with hash and decreasing expiries
- HTLCs propagate: Each hop creates an HTLC to the next
- Recipient reveals preimage: Claims final HTLC
- Preimage propagates back: Each hop claims their incoming HTLC
- Settlement complete: All HTLCs resolved atomically
Example Route
Alice → Bob → Carol → Dave
Alice creates HTLC to Bob:
- Amount: 1000 + 3 sats (fees)
- Hash: SHA256(preimage)
- Expiry: Block 850,040
Bob creates HTLC to Carol:
- Amount: 1000 + 1 sats (fees)
- Hash: SHA256(preimage) [same]
- Expiry: Block 850,030 [earlier]
Carol creates HTLC to Dave:
- Amount: 1000 sats
- Hash: SHA256(preimage) [same]
- Expiry: Block 850,020 [earliest]
Why Decreasing Expiries?
Each hop needs an expiry delta (CLTV delta) buffer to:
- Have time to claim incoming HTLC after learning preimage
- Handle blockchain congestion
- Account for clock differences between nodes
Rule: Outgoing HTLC expiry < Incoming HTLC expiry (by at least cltv_expiry_delta)
HTLC Script Structure
HTLCs in commitment transactions use this script pattern:
# Offered HTLC (you're offering payment)
OP_DUP OP_HASH160 <revocation_pubkey_hash> OP_EQUAL
OP_IF
OP_CHECKSIG # Revocation path
OP_ELSE
<remote_htlc_pubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
OP_IF
OP_HASH160 <payment_hash> OP_EQUALVERIFY # Success path
2 OP_SWAP <local_htlc_pubkey> 2 OP_CHECKMULTISIG
OP_ELSE
OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
OP_CHECKSIG # Timeout path
OP_ENDIF
OP_ENDIF
HTLC Verification
HTLC States
An HTLC in a channel transitions through these states:
| State | Description | Outcome |
|---|---|---|
| Offered | Sent to peer, awaiting response | → Accepted or Failed |
| Accepted | Peer acknowledged, awaiting preimage | → Settled or Failed |
| Settled | Preimage revealed, funds transferred | Complete |
| Failed | Timeout or error, funds returned | Complete |
Lifecycle:
Offered → Accepted → Settled (success)
↓ ↓
Failed Failed (timeout/error)
HTLC Security Properties
Atomicity
Either the entire payment succeeds or fails completely:
- All HTLCs in the route share the same payment hash
- Revealing the preimage settles all HTLCs
- Timeout returns all funds to senders
Hash Lock Security
- Preimage must be exactly 32 bytes
- SHA256 is collision-resistant
- Only the recipient knows the preimage initially
Time Lock Security
- CLTV (CheckLockTimeVerify) enforced by Bitcoin consensus
- Sufficient delta prevents race conditions
- Allows time for breach detection
Common Issues
HTLC Timeout
Problem: HTLC expires before payment completes.
Causes:
- Route too long (accumulated CLTV deltas)
- Slow intermediate nodes
- Network congestion
Solutions:
- Increase
max_cltv_expirysetting - Use shorter routes
- Retry with different path
Stuck HTLCs
Problem: HTLC neither settles nor fails.
Causes:
- Peer offline
- Bug in implementation
- Network partition
Solutions:
- Wait for CLTV expiry
- Force close channel if necessary
Summary
HTLCs are the atomic building blocks of Lightning payments:
- Hash locks ensure only the recipient can claim funds
- Time locks enable safe routing through untrusted intermediaries
- Decreasing expiries prevent routing attacks
- Atomicity guarantees all-or-nothing settlement
Related Topics
- Routing Fees - How routing fees work
- Multi-Part Payments - Splitting payments across routes
- Onion Routing - Privacy in payment routing
