Menu
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

AspectValue
StatusFinal
LayerChannel
PurposeChannel lifecycle management
DependenciesBOLT-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

ParameterTypical ValuePurpose
max_htlc_value_in_flight_msatChannel capacityRisk limit
channel_reserve_satoshis1% of capacityPenalty stake
max_accepted_htlcs483Script size limit
htlc_minimum_msat1000Dust prevention
to_self_delay144 blocksRevocation 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

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"}
  ]
}