Payment Routing
How Lightning finds payment paths through the network. Pathfinding algorithms, onion routing, and route optimization.
Payment Routing
Lightning payments don’t require direct channels between sender and recipient. The network routes payments through intermediaries, with each hop forwarding the payment to the next.
Why Routing Matters for Agents
| Benefit | Description |
|---|---|
| Connectivity | Pay anyone reachable via network paths |
| Privacy | Onion routing hides payment details |
| Competition | Multiple routes drive fees down |
| Resilience | Failed paths can be retried |
Network Topology
The Lightning Network is a graph of nodes connected by channels:
┌─────┐
│ D │
/ \
┌─────┐ ┌─────┐
│ A │─────────│ C │─────┐
└─────┘ └─────┘ │
\ / │
\ / │
┌─────┐ ┌─────┐
│ B │──────────────│ E │
└─────┘ └─────┘
Nodes: Lightning nodes (wallets, routing nodes) Edges: Payment channels with capacity
Pathfinding
The Problem
Given:
- Source node (sender)
- Destination node (recipient)
- Amount to send
Find:
- Path with sufficient liquidity
- Minimizing fees and hops
Dijkstra’s Algorithm
Most implementations use Dijkstra’s shortest path algorithm weighted by:
cost = base_fee + (amount × fee_rate) + risk_factor
base_fee: Fixed cost per hop (typically 0-1000 msat) fee_rate: Proportional fee (typically 1-1000 ppm) risk_factor: Penalty for unreliable channels
Multi-Path Payments (MPP)
Large payments can be split across multiple routes:
Payment: 100,000 sats
Route 1: Alice → Carol → Bob (50,000 sats)
Route 2: Alice → Dave → Bob (30,000 sats)
Route 3: Alice → Eve → Bob (20,000 sats)
Benefits:
- Use channels with limited liquidity
- Better success rate for large payments
- Privacy (observers see smaller amounts)
Onion Routing
Lightning uses onion routing to hide payment details from intermediaries.
Layered Encryption
┌──────────────────────────────────────────────┐
│ Carol's layer │
│ ┌──────────────────────────────────────────┐ │
│ │ Dave's layer │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ Eve's layer │ │ │
│ │ │ ┌──────────────────────────────────┐ │ │ │
│ │ │ │ Final destination (Bob) │ │ │ │
│ │ │ └──────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
Each node:
- Decrypts their layer
- Learns only the next hop
- Forwards the remaining onion
What Each Node Sees
| Node | Knows | Doesn’t Know |
|---|---|---|
| Sender | Full route, amount | - |
| Intermediate | Previous hop, next hop | Origin, destination, amount |
| Recipient | Sender (sometimes), amount | Route taken |
Onion Packet Structure
┌─────────────────────────────────────────┐
│ Version (1 byte) │
│ Public Key (33 bytes) │
│ Encrypted Routing Info (1300 bytes) │
│ HMAC (32 bytes) │
└─────────────────────────────────────────┘
Total onion size: 1366 bytes (fits any route up to 20 hops)
Gossip Protocol
Nodes learn about the network through gossip—announcements propagated peer-to-peer.
Message Types
| Message | Purpose |
|---|---|
node_announcement | Node info (alias, color, features) |
channel_announcement | New channel created |
channel_update | Fee/policy changes |
Channel Update Fields
channel_update:
channel_id: 123456789
timestamp: 1706745600
flags: 0x01 # direction
cltv_expiry_delta: 40
htlc_minimum_msat: 1000
fee_base_msat: 1000
fee_proportional_millionths: 100
htlc_maximum_msat: 1000000000
Fee Calculation
Routing fees are calculated per hop:
fee = base_fee_msat + (amount_msat × fee_rate_ppm / 1,000,000)
Example:
- Amount: 100,000 sats (100,000,000 msat)
- Base fee: 1000 msat (1 sat)
- Fee rate: 100 ppm
fee = 1000 + (100,000,000 × 100 / 1,000,000)
fee = 1000 + 10,000
fee = 11,000 msat (11 sats)
Fee Accumulation
Fees accumulate backwards through the route:
Alice → Carol → Dave → Bob
fee=10 fee=5
Bob receives: 100,000 sats
Dave forwards: 100,000 + 5 = 100,005 sats
Carol forwards: 100,005 + 10 = 100,015 sats
Alice sends: 100,015 sats
Route Hints
For private channels or mobile wallets, recipients provide route hints in invoices:
Invoice route hints:
- Node: 03abc...
Channel: 123456
Fee base: 1000
Fee rate: 100
CLTV delta: 40
This tells the sender how to reach the recipient’s private node.
Pathfinding Strategies
Shortest Path
Minimize total fees:
weight = Σ(base_fee + amount × fee_rate)
Reliability-Weighted
Penalize unreliable channels:
weight = fee + (1 - success_probability) × penalty
Privacy-Optimized
Prefer paths that obscure payment patterns:
- Avoid popular nodes
- Use longer paths
- Randomize route selection
Agent Implementation
Finding a Route
# Via LND
routes = lnd.query_routes(
pub_key=destination_pubkey,
amt=amount_sat,
num_routes=3,
fee_limit={"fixed": 1000} # max 1000 sats
)
for route in routes.routes:
print(f"Hops: {len(route.hops)}")
print(f"Total fees: {route.total_fees_msat} msat")
print(f"Total time lock: {route.total_time_lock} blocks")
Sending via Route
# Send with specific route
result = lnd.send_to_route(
payment_hash=payment_hash,
route=routes.routes[0]
)
if result.failure:
print(f"Failed at hop {result.failure.failure_source_index}")
print(f"Reason: {result.failure.code}")
Handling Failures
def send_with_retry(destination, amount, max_attempts=3):
excluded_channels = []
for attempt in range(max_attempts):
routes = lnd.query_routes(
pub_key=destination,
amt=amount,
ignored_pairs=excluded_channels
)
result = lnd.send_to_route(
payment_hash=payment_hash,
route=routes.routes[0]
)
if result.payment_preimage:
return result # Success
# Add failed channel to exclusion list
failed_hop = result.failure.failure_source_index
failed_channel = routes.routes[0].hops[failed_hop].chan_id
excluded_channels.append(failed_channel)
raise Exception("Payment failed after retries")
Common Routing Failures
| Failure | Cause | Solution |
|---|---|---|
TEMPORARY_CHANNEL_FAILURE | Insufficient liquidity | Try different route |
UNKNOWN_NEXT_PEER | Node offline | Exclude from route |
FEE_INSUFFICIENT | Fees changed | Recalculate route |
INCORRECT_CLTV_EXPIRY | Timelock mismatch | Use updated channel info |
CHANNEL_DISABLED | Channel inactive | Exclude channel |
Privacy Considerations
Timing Analysis
- Payment timing can correlate sender/receiver
- Mitigation: Random delays (not widely implemented)
Amount Correlation
- Same amount at hops reveals route
- Mitigation: MPP (splits into smaller amounts)
Node Correlation
- Source node sees full route
- Mitigation: Trampoline routing (delegate pathfinding)
Related Topics
- HTLCs - How payments traverse routes
- Channels - The edges in the network graph
- Fees - Fee structures and optimization
- BOLT-04 - Onion routing specification
- BOLT-07 - Gossip protocol specification
Machine-Readable Summary
{
"topic": "payment-routing",
"key_concepts": [
"pathfinding",
"onion-routing",
"gossip-protocol",
"fee-calculation"
],
"algorithms": [
"dijkstra",
"multi-path-payments"
],
"privacy_features": [
"layered-encryption",
"intermediate-node-blindness"
]
}