Menu
BOLT-bolt-01 Final

BOLT-01: Base Protocol

Lightning Network base protocol specification. Message format, feature bits, and connection establishment.

Type Basis of Lightning Technology
Number bolt-01
Status Final
Authors Lightning Network Developers
Original https://github.com/lightning/bolts/blob/master/01-messaging.md

BOLT-01: Base Protocol

BOLT-01 defines the fundamental message format and feature negotiation for Lightning Network communication. All other BOLTs build on these primitives.

Specification Summary

AspectValue
StatusFinal
LayerTransport
PurposeMessage framing and features
DependenciesBOLT-08 (encryption)

Message Format

All Lightning messages follow this structure:

┌──────────────────────────────────────────┐
│ type (2 bytes, big-endian)               │
├──────────────────────────────────────────┤
│ payload (variable length)                │
└──────────────────────────────────────────┘

Type ranges:

RangePurpose
0-32767P2P messages (requires handshake)
32768-65535Custom/experimental

Message Size Limits

  • Maximum message size: 65535 bytes (after encryption)
  • Includes 2-byte type field
  • Payload: up to 65533 bytes

Core Messages

init (type 16)

Sent immediately after connection establishment:

┌─────────────────────────────────────────┐
│ gflen (2 bytes): global features length │
│ globalfeatures (gflen bytes)            │
│ flen (2 bytes): features length         │
│ features (flen bytes)                   │
│ [tlvs]: optional TLV stream             │
└─────────────────────────────────────────┘

error (type 17)

Report errors to peer:

┌─────────────────────────────────────────┐
│ channel_id (32 bytes)                   │
│ len (2 bytes): data length              │
│ data (len bytes): error message         │
└─────────────────────────────────────────┘

Special channel_id: All zeros means connection-level error.

warning (type 1)

Non-fatal warning (added later):

┌─────────────────────────────────────────┐
│ channel_id (32 bytes)                   │
│ len (2 bytes): data length              │
│ data (len bytes): warning message       │
└─────────────────────────────────────────┘

ping (type 18)

Keep-alive and latency measurement:

┌─────────────────────────────────────────┐
│ num_pong_bytes (2 bytes)                │
│ byteslen (2 bytes)                      │
│ ignored (byteslen bytes)                │
└─────────────────────────────────────────┘

pong (type 19)

Response to ping:

┌─────────────────────────────────────────┐
│ byteslen (2 bytes)                      │
│ ignored (byteslen bytes)                │
└─────────────────────────────────────────┘

Feature Bits

Features are negotiated via bit vectors in init messages.

Bit Interpretation

Bit PositionMeaning
Even (0, 2, 4…)Required—disconnect if not understood
Odd (1, 3, 5…)Optional—ignore if not understood

Feature Pairs

Each feature uses two bits:

  • Bit N (even): “I require this”
  • Bit N+1 (odd): “I support this”

Core Features

BitsNameDescription
0/1data_loss_protectChannel reestablish includes state
4/5upfront_shutdown_scriptPre-agreed shutdown address
6/7gossip_queriesGossip query support
8/9var_onion_optinVariable-length onion
10/11gossip_queries_exExtended gossip queries
12/13static_remotekeyStatic output keys
14/15payment_secretPayment secret in invoices
16/17basic_mppMulti-path payments
18/19option_support_large_channelWumbo channels
20/21option_anchor_outputsAnchor outputs
22/23option_anchors_zero_fee_htlc_txZero-fee HTLC anchors

Feature Negotiation

Connection Establishment

Alice                              Bob
  │                                  │
  │──────── TCP connect ────────────→│
  │                                  │
  │←───── Noise handshake ──────────→│
  │         (BOLT-08)                │
  │                                  │
  │──────── init ───────────────────→│
  │←─────── init ────────────────────│
  │                                  │
  │    Features negotiated           │
  │                                  │

Negotiation Rules

  1. If peer sets unknown even bit: disconnect
  2. If peer sets unknown odd bit: ignore
  3. Connection features = intersection of both init messages
  4. Channel features negotiated separately (channel_type)

TLV Format

Type-Length-Value encoding for extensibility:

┌─────────────────────────────────────────┐
│ type (BigSize)                          │
│ length (BigSize)                        │
│ value (length bytes)                    │
└─────────────────────────────────────────┘

BigSize Encoding

Variable-length integer:

RangeEncoding
0-0xfc1 byte (value)
0xfd-0xffff0xfd + 2 bytes
0x10000-0xffffffff0xfe + 4 bytes
larger0xff + 8 bytes

Agent Implementation

Parsing Messages

import struct

def parse_message(data: bytes) -> tuple[int, bytes]:
    """Parse Lightning message into type and payload."""
    if len(data) < 2:
        raise ValueError("Message too short")

    msg_type = struct.unpack('>H', data[:2])[0]
    payload = data[2:]

    return msg_type, payload

def create_message(msg_type: int, payload: bytes) -> bytes:
    """Create Lightning message from type and payload."""
    return struct.pack('>H', msg_type) + payload

Feature Handling

def has_feature(features: bytes, bit: int) -> bool:
    """Check if feature bit is set."""
    byte_index = bit // 8
    bit_index = bit % 8

    if byte_index >= len(features):
        return False

    # Features are stored little-endian
    return bool(features[byte_index] & (1 << bit_index))

def requires_feature(features: bytes, bit: int) -> bool:
    """Check if feature is required (even bit set)."""
    return has_feature(features, bit & ~1)  # Even bit

def supports_feature(features: bytes, bit: int) -> bool:
    """Check if feature is supported (any bit in pair)."""
    return has_feature(features, bit & ~1) or has_feature(features, bit | 1)

Init Message

def create_init(features: bytes, networks: list[bytes] = None) -> bytes:
    """Create init message."""
    payload = struct.pack('>H', 0)  # global features (legacy, empty)
    payload += struct.pack('>H', len(features))
    payload += features

    if networks:
        # Add networks TLV (type 1)
        tlv = create_tlv(1, b''.join(networks))
        payload += tlv

    return create_message(16, payload)

Error Handling

Error Severity

Error TypeAction
Connection errorClose TCP connection
Channel errorFail/close specific channel
WarningLog, continue operation

All-Zero Channel ID

Channel ID of 32 zero bytes indicates error applies to entire connection:

ALL_ZERO_CHANNEL = b'\x00' * 32

def is_connection_error(channel_id: bytes) -> bool:
    return channel_id == ALL_ZERO_CHANNEL

Machine-Readable Summary

{
  "bolt": "01",
  "title": "Base Protocol",
  "status": "final",
  "messages": [
    {"type": 16, "name": "init"},
    {"type": 17, "name": "error"},
    {"type": 1, "name": "warning"},
    {"type": 18, "name": "ping"},
    {"type": 19, "name": "pong"}
  ],
  "key_concepts": [
    "message-format",
    "feature-bits",
    "tlv-encoding"
  ]
}