BOLT-bolt-02 Final
BOLT-02: Peer Protocol
Lightning channel management protocol. Channel establishment, operation, and closure messages.
| Type | Basis of Lightning Technology |
| Number | bolt-02 |
| Status | Final |
| Authors | Lightning Network Developers |
| Original | https://github.com/lightning/bolts/blob/master/02-peer-protocol.md |
| Requires |
BOLT-02: Peer Protocol
BOLT-02 defines the messages for establishing, operating, and closing Lightning payment channels between two peers.
Specification Summary
| Aspect | Value |
|---|---|
| Status | Final |
| Layer | Channel |
| Purpose | Channel lifecycle management |
| Dependencies | BOLT-01, BOLT-03 |
Channel Lifecycle
┌─────────────┐
│ Closed │
└──────┬──────┘
│ open_channel / accept_channel
↓
┌─────────────┐
│ Funding │
└──────┬──────┘
│ funding_created / funding_signed
↓
┌─────────────┐
│ Awaiting │
│ Confirmation│
└──────┬──────┘
│ funding_locked / channel_ready
↓
┌─────────────┐
│ Normal │ ←── HTLC operations
└──────┬──────┘
│ shutdown
↓
┌─────────────┐
│ Closing │
└──────┬──────┘
│ closing_signed
↓
┌─────────────┐
│ Closed │
└─────────────┘
Channel Establishment
open_channel (type 32)
Initiator proposes channel parameters:
┌─────────────────────────────────────────────┐
│ chain_hash (32 bytes) │
│ temporary_channel_id (32 bytes) │
│ funding_satoshis (8 bytes) │
│ push_msat (8 bytes) │
│ dust_limit_satoshis (8 bytes) │
│ max_htlc_value_in_flight_msat (8 bytes) │
│ channel_reserve_satoshis (8 bytes) │
│ htlc_minimum_msat (8 bytes) │
│ feerate_per_kw (4 bytes) │
│ to_self_delay (2 bytes) │
│ max_accepted_htlcs (2 bytes) │
│ funding_pubkey (33 bytes) │
│ revocation_basepoint (33 bytes) │
│ payment_basepoint (33 bytes) │
│ delayed_payment_basepoint (33 bytes) │
│ htlc_basepoint (33 bytes) │
│ first_per_commitment_point (33 bytes) │
│ channel_flags (1 byte) │
│ [tlvs] │
└─────────────────────────────────────────────┘
accept_channel (type 33)
Responder accepts with their parameters:
┌─────────────────────────────────────────────┐
│ temporary_channel_id (32 bytes) │
│ dust_limit_satoshis (8 bytes) │
│ max_htlc_value_in_flight_msat (8 bytes) │
│ channel_reserve_satoshis (8 bytes) │
│ htlc_minimum_msat (8 bytes) │
│ minimum_depth (4 bytes) │
│ to_self_delay (2 bytes) │
│ max_accepted_htlcs (2 bytes) │
│ funding_pubkey (33 bytes) │
│ revocation_basepoint (33 bytes) │
│ payment_basepoint (33 bytes) │
│ delayed_payment_basepoint (33 bytes) │
│ htlc_basepoint (33 bytes) │
│ first_per_commitment_point (33 bytes) │
│ [tlvs] │
└─────────────────────────────────────────────┘
funding_created (type 34)
Initiator sends funding transaction info:
┌─────────────────────────────────────────────┐
│ temporary_channel_id (32 bytes) │
│ funding_txid (32 bytes) │
│ funding_output_index (2 bytes) │
│ signature (64 bytes) │
└─────────────────────────────────────────────┘
funding_signed (type 35)
Responder acknowledges:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ signature (64 bytes) │
└─────────────────────────────────────────────┘
channel_ready (type 36)
Both sides send when funding is confirmed:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ second_per_commitment_point (33 bytes) │
│ [tlvs] │
└─────────────────────────────────────────────┘
Channel ID Calculation
def calculate_channel_id(funding_txid: bytes, output_index: int) -> bytes:
"""Calculate channel_id from funding transaction."""
# XOR funding_txid with output_index in last 2 bytes
channel_id = bytearray(funding_txid)
channel_id[-2] ^= (output_index >> 8) & 0xff
channel_id[-1] ^= output_index & 0xff
return bytes(channel_id)
Normal Operation
HTLC Messages
update_add_htlc (type 128)
Add an HTLC to the channel:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ id (8 bytes) │
│ amount_msat (8 bytes) │
│ payment_hash (32 bytes) │
│ cltv_expiry (4 bytes) │
│ onion_routing_packet (1366 bytes) │
└─────────────────────────────────────────────┘
update_fulfill_htlc (type 130)
Claim an HTLC with preimage:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ id (8 bytes) │
│ payment_preimage (32 bytes) │
└─────────────────────────────────────────────┘
update_fail_htlc (type 131)
Fail an HTLC:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ id (8 bytes) │
│ len (2 bytes) │
│ reason (len bytes) │
└─────────────────────────────────────────────┘
Commitment Updates
commitment_signed (type 132)
Sign new commitment transaction:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ signature (64 bytes) │
│ num_htlcs (2 bytes) │
│ htlc_signature (num_htlcs × 64 bytes) │
└─────────────────────────────────────────────┘
revoke_and_ack (type 133)
Revoke previous commitment:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ per_commitment_secret (32 bytes) │
│ next_per_commitment_point (33 bytes) │
└─────────────────────────────────────────────┘
Payment Flow
Sending Payment
Sender Receiver
│ │
│──── update_add_htlc ────────────────────→│
│──── commitment_signed ──────────────────→│
│←─── revoke_and_ack ──────────────────────│
│←─── commitment_signed ───────────────────│
│──── revoke_and_ack ─────────────────────→│
│ │
│ HTLC now irrevocably added │
│ │
Fulfilling Payment
Sender Receiver
│ │
│←─── update_fulfill_htlc ─────────────────│
│←─── commitment_signed ───────────────────│
│──── revoke_and_ack ─────────────────────→│
│──── commitment_signed ──────────────────→│
│←─── revoke_and_ack ──────────────────────│
│ │
│ Payment complete │
│ │
Channel Closure
Cooperative Close
shutdown (type 38)
Initiate graceful close:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ len (2 bytes) │
│ scriptpubkey (len bytes) │
└─────────────────────────────────────────────┘
closing_signed (type 39)
Negotiate closing fee:
┌─────────────────────────────────────────────┐
│ channel_id (32 bytes) │
│ fee_satoshis (8 bytes) │
│ signature (64 bytes) │
└─────────────────────────────────────────────┘
Closure Flow
Alice Bob
│ │
│──── shutdown ──────────────────────────→│
│←─── shutdown ───────────────────────────│
│ │
│ No more HTLCs can be added │
│ Wait for pending HTLCs to resolve │
│ │
│──── closing_signed (fee=1000) ─────────→│
│←─── closing_signed (fee=800) ───────────│
│──── closing_signed (fee=900) ─────────→│
│←─── closing_signed (fee=900) ───────────│
│ │
│ Agreement! Broadcast closing tx │
│ │
Channel Parameters
Limits
| Parameter | Typical Value | Purpose |
|---|---|---|
max_htlc_value_in_flight_msat | Channel capacity | Risk limit |
channel_reserve_satoshis | 1% of capacity | Penalty stake |
max_accepted_htlcs | 483 | Script size limit |
htlc_minimum_msat | 1000 | Dust prevention |
to_self_delay | 144 blocks | Revocation time |
Dust Limit
Minimum output size to prevent uneconomical UTXOs:
# Typical dust limits
P2WPKH_DUST = 294 # satoshis
P2WSH_DUST = 330
ANCHOR_DUST = 330
Agent Implementation
Channel State Machine
from enum import Enum
class ChannelState(Enum):
OPENING = 1
FUNDING = 2
AWAITING_LOCKIN = 3
NORMAL = 4
SHUTDOWN = 5
CLOSING = 6
CLOSED = 7
class Channel:
def __init__(self, channel_id: bytes):
self.channel_id = channel_id
self.state = ChannelState.OPENING
self.local_balance = 0
self.remote_balance = 0
self.pending_htlcs = []
def on_channel_ready(self):
if self.state == ChannelState.AWAITING_LOCKIN:
self.state = ChannelState.NORMAL
def on_shutdown(self):
if self.state == ChannelState.NORMAL:
self.state = ChannelState.SHUTDOWN
Related BOLTs
Machine-Readable Summary
{
"bolt": "02",
"title": "Peer Protocol",
"status": "final",
"messages": [
{"type": 32, "name": "open_channel"},
{"type": 33, "name": "accept_channel"},
{"type": 34, "name": "funding_created"},
{"type": 35, "name": "funding_signed"},
{"type": 36, "name": "channel_ready"},
{"type": 38, "name": "shutdown"},
{"type": 39, "name": "closing_signed"},
{"type": 128, "name": "update_add_htlc"},
{"type": 130, "name": "update_fulfill_htlc"},
{"type": 131, "name": "update_fail_htlc"},
{"type": 132, "name": "commitment_signed"},
{"type": 133, "name": "revoke_and_ack"}
]
}