This specification describes simple node discovery, channel discovery, and channel update mechanisms that do not rely on a third-party to disseminate the information.
Node and channel discovery serve two different purposes:
- Node discovery allows nodes to broadcast their ID, host, and port, so that other nodes can open connections and establish payment channels with them.
- Channel discovery allows the creation and maintenance of a local view of the network's topology, so that a node can discover routes to desired destinations.
To support channel and node discovery, three gossip messages are supported:
-
For node discovery, peers exchange
node_announcementmessages, which supply additional information about the nodes. There may be multiplenode_announcementmessages, in order to update the node information. -
For channel discovery, peers in the network exchange
channel_announcementmessages containing information regarding new channels between the two nodes. They can also exchangechannel_updatemessages, which update information about a channel. There can only be one validchannel_announcementfor any channel, but at least twochannel_updatemessages are expected.
- Definition of
short_channel_id - The
announcement_signaturesMessage - The
channel_announcementMessage - The
node_announcementMessage - The
channel_updateMessage - Query Messages
- Rebroadcasting
- HTLC Fees
- Pruning the Network View
- Recommendations for Routing
- References
The short_channel_id is the unique description of the funding transaction.
It is constructed as follows:
- the most significant 3 bytes: indicating the block height
- the next 3 bytes: indicating the transaction index within the block
- the least significant 2 bytes: indicating the output index that pays to the channel.
The standard human readable format for short_channel_id is created
by printing the above components, in the order:
block height, transaction index, and output index.
Each component is printed as a decimal number,
and separated from each other by the small letter x.
For example, a short_channel_id might be written as 539268x845x1,
indicating a channel on the output 1 of the transaction at index 845
of the block at height 539268.
The short_channel_id human readable format is designed
so that double-clicking or double-tapping it will select the entire ID
on most systems.
Humans prefer decimal when reading numbers,
so the ID components are written in decimal.
The small letter x is used since on most fonts,
the x is visibly smaller than decimal digits,
making it easy to visibly group each component of the ID.
This is a direct message between the two endpoints of a channel and serves as an opt-in mechanism to allow the announcement of the channel to the rest of the network.
It contains the necessary signatures, by the sender, to construct the channel_announcement message.
- type: 259 (
announcement_signatures) - data:
- [
channel_id:channel_id] - [
short_channel_id:short_channel_id] - [
signature:node_signature] - [
signature:bitcoin_signature]
- [
The willingness of the initiating node to announce the channel is signaled during channel opening by setting the announce_channel bit in channel_flags (see BOLT #2).
The announcement_signatures message is created by constructing a channel_announcement message,
corresponding to the newly confirmed channel funding transaction, and signing it with the secrets
matching an endpoint's node_id and bitcoin_key.
A node:
- If the
open_channelmessage has theannounce_channelbit set AND ashutdownmessage has not been sent:- After
channel_readyhas been sent and received AND the funding transaction has enough confirmations to ensure that it won't be reorganized:- MUST send
announcement_signaturesfor the funding transaction.
- MUST send
- After
- Otherwise:
- MUST NOT send the
announcement_signaturesmessage.
- MUST NOT send the
- Upon reconnection (once the above timing requirements have been met):
- If it has NOT previously received
announcement_signaturesfor the funding transaction:- MUST send its own
announcement_signaturesmessage.
- MUST send its own
- If it receives
announcement_signaturesfor the funding transaction:- MUST respond with its own
announcement_signaturesmessage.
- MUST respond with its own
- If it has NOT previously received
A recipient node:
- If the
short_channel_idis NOT correct:- SHOULD send a
warningand close the connection, or send anerrorand fail the channel.
- SHOULD send a
- If the
node_signatureOR thebitcoin_signatureis NOT correct:- MAY send a
warningand close the connection, or send anerrorand fail the channel.
- MAY send a
- If it has sent AND received a valid
announcement_signaturesmessage:- If the funding transaction has at least 6 confirmations:
- SHOULD queue the
channel_announcementmessage for its peers.
- SHOULD queue the
- If the funding transaction has at least 6 confirmations:
- If it has not sent
channel_ready:- SHOULD defer handling the
announcement_signaturesuntil after it has sentchannel_ready.
- SHOULD defer handling the
Channels must not be announced before the funding transaction has enough
confirmations, because a blockchain reorganization would otherwise invalidate
the short_channel_id.
This gossip message contains ownership information regarding a channel. It ties
each on-chain Bitcoin key to the associated Lightning node key, and vice-versa.
The channel is not practically usable until at least one side has announced
its fee levels and expiry, using channel_update.
Proving the existence of a channel between node_1 and node_2 requires:
- proving that the funding transaction pays to
bitcoin_key_1andbitcoin_key_2 - proving that
node_1ownsbitcoin_key_1 - proving that
node_2ownsbitcoin_key_2
Assuming that all nodes know the unspent transaction outputs, the first proof is
accomplished by a node finding the output given by the short_channel_id and
verifying that it is indeed a P2WSH funding transaction output for those keys
specified in BOLT #3.
The last two proofs are accomplished through explicit signatures:
bitcoin_signature_1 and bitcoin_signature_2 are generated for each
bitcoin_key and each of the corresponding node_ids are signed.
It's also necessary to prove that node_1 and node_2 both agree on the
announcement message: this is accomplished by having a signature from each
node_id (node_signature_1 and node_signature_2) signing the message.
- type: 256 (
channel_announcement) - data:
- [
signature:node_signature_1] - [
signature:node_signature_2] - [
signature:bitcoin_signature_1] - [
signature:bitcoin_signature_2] - [
u16:len] - [
len*byte:features] - [
chain_hash:chain_hash] - [
short_channel_id:short_channel_id] - [
point:node_id_1] - [
point:node_id_2] - [
point:bitcoin_key_1] - [
point:bitcoin_key_2]
- [
The origin node:
- MUST set
chain_hashto the 32-byte hash that uniquely identifies the chain that the channel was opened within:- for the Bitcoin blockchain:
- MUST set
chain_hashvalue (encoded in hex) equal to6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000.
- MUST set
- for the Bitcoin blockchain:
- MUST set
short_channel_idto refer to the confirmed funding transaction, as specified in BOLT #2.- Note: the corresponding output MUST be a P2WSH, as described in BOLT #3.
- MUST set
node_id_1andnode_id_2to the public keys of the two nodes operating the channel, such thatnode_id_1is the lexicographically-lesser of the two compressed keys sorted in ascending lexicographic order. - MUST set
bitcoin_key_1andbitcoin_key_2tonode_id_1andnode_id_2's respectivefunding_pubkeys. - MUST compute the double-SHA256 hash
hof the message, beginning at offset 256, up to the end of the message.- Note: the hash skips the 4 signatures but hashes the rest of the message, including any future fields appended to the end.
- MUST set
node_signature_1andnode_signature_2to valid signatures of the hashh(usingnode_id_1andnode_id_2's respective secrets). - MUST set
bitcoin_signature_1andbitcoin_signature_2to valid signatures of the hashh(usingbitcoin_key_1andbitcoin_key_2's respective secrets). - MUST set
featuresbased on what features were negotiated for this channel, according to BOLT #9 - MUST set
lento the minimum length required to hold thefeaturesbits it sets. - If the funding transaction has less than 6 confirmations:
- MUST NOT send
channel_announcement.
- MUST NOT send
The receiving node:
- MUST verify the integrity AND authenticity of the message by verifying the signatures.
- if there is an unknown even bit in the
featuresfield:- MUST NOT attempt to route messages through the channel.
- if the
short_channel_id's output does NOT correspond to a P2WSH (usingbitcoin_key_1andbitcoin_key_2, as specified in BOLT #3) OR the output is spent:- MUST ignore the message.
- if the specified
chain_hashis unknown to the receiver:- MUST ignore the message.
- if the
short_channel_id's output does NOT have at least 6 confirmations:- MAY accept the message if the output is close to 6 confirmations, in case the receiving node hasn't received the latest block(s) yet.
- otherwise:
- SHOULD ignore the message.
- otherwise:
- if
bitcoin_signature_1,bitcoin_signature_2,node_signature_1ORnode_signature_2are invalid OR NOT correct:- SHOULD send a
warning. - MAY close the connection.
- MUST ignore the message.
- SHOULD send a
- otherwise:
- if
node_id_1ORnode_id_2are blacklisted:- SHOULD ignore the message.
- otherwise:
- if the transaction referred to was NOT previously announced as a
channel:
- SHOULD queue the message for rebroadcasting.
- MAY choose NOT to for messages longer than the minimum expected length.
- if the transaction referred to was NOT previously announced as a
channel:
- if it has previously received a valid
channel_announcement, for the same transaction, in the same block, but for a differentnode_id_1ornode_id_2:- SHOULD blacklist the previous message's
node_id_1andnode_id_2, as well as thisnode_id_1andnode_id_2AND forget any channels connected to them.
- SHOULD blacklist the previous message's
- otherwise:
- SHOULD store this
channel_announcement.
- SHOULD store this
- if
- if
- once its funding output has been spent OR reorganized out:
- SHOULD forget a channel after a 12-block delay.
Both nodes are required to sign to indicate they are willing to route other payments via this channel (i.e. be part of the public network); requiring their Bitcoin signatures proves that they control the channel.
The blacklisting of conflicting nodes disallows multiple different announcements. Such conflicting announcements should never be broadcast by any node, as this implies that keys have leaked.
While channels should not be advertised before they are sufficiently deep, the requirement against rebroadcasting only applies if the transaction has not moved to a different block.
In order to avoid storing excessively large messages, yet still allow for reasonable future expansion, nodes are permitted to restrict rebroadcasting (perhaps statistically).
New channel features are possible in the future: backwards compatible (or optional) features will have odd feature bits, while incompatible features will have even feature bits ("It's OK to be odd!").
A delay of 12 blocks is used when forgetting a channel on funding output spend
as to permit a new channel_announcement to propagate which indicates this
channel was spliced.
This gossip message allows a node to indicate extra data associated with it, in addition to its public key. To avoid trivial denial of service attacks, nodes not associated with an already known channel are ignored.
- type: 257 (
node_announcement) - data:
- [
signature:signature] - [
u16:flen] - [
flen*byte:features] - [
u32:timestamp] - [
point:node_id] - [
3*byte:rgb_color] - [
32*byte:alias] - [
u16:addrlen] - [
addrlen*byte:addresses]
- [
timestamp allows for the ordering of messages, in the case of multiple
announcements. rgb_color and alias allow intelligence services to assign
nodes colors like black and cool monikers like 'IRATEMONK' and 'WISTFULTOLL'.
addresses allows a node to announce its willingness to accept incoming network
connections: it contains a series of address descriptors for connecting to the
node. The first byte describes the address type and is followed by the
appropriate number of bytes for that type.
The following address descriptor types are defined:
1: ipv4; data =[4:ipv4_addr][2:port](length 6)2: ipv6; data =[16:ipv6_addr][2:port](length 18)3: Deprecated (length 12). Used to contain Tor v2 onion services.4: Tor v3 onion service; data =[35:onion_addr][2:port](length 37)- version 3 (prop224)
onion service addresses; Encodes:
[32:32_byte_ed25519_pubkey] || [2:checksum] || [1:version], wherechecksum = sha3(".onion checksum" || pubkey || version)[:2].
- version 3 (prop224)
onion service addresses; Encodes:
5: DNS hostname; data =[1:hostname_len][hostname_len:hostname][2:port](length up to 258)hostnamebytes MUST be ASCII characters.- Non-ASCII characters MUST be encoded using Punycode: https://en.wikipedia.org/wiki/Punycode
The origin node:
- MUST set
timestampto be greater than that of any previousnode_announcementit has previously created.- MAY base it on a UNIX timestamp.
- MUST set
signatureto the signature of the double-SHA256 of the entire remaining packet aftersignature(using the key given bynode_id). - MAY set
aliasANDrgb_colorto customize its appearance in maps and graphs.- Note: the first byte of
rgb_coloris the red value, the second byte is the green value, and the last byte is the blue value.
- Note: the first byte of
- MUST set
aliasto a valid UTF-8 string, with anyaliastrailing-bytes equal to 0. - SHOULD fill
addresseswith an address descriptor for each public network address that expects incoming connections. - MUST set
addrlento the number of bytes inaddresses. - MUST place address descriptors in ascending order.
- SHOULD NOT place any zero-typed address descriptors anywhere.
- SHOULD use placement only for aligning fields that follow
addresses. - MUST NOT create a
type 1,type 2ortype 5address descriptor withportequal to 0. - SHOULD ensure
ipv4_addrANDipv6_addrare routable addresses. - MUST set
featuresaccording to BOLT #9 - SHOULD set
flento the minimum length required to hold thefeaturesbits it sets. - SHOULD not announce a Tor v2 onion service.
- MUST NOT announce more than one
type 5DNS hostname.
The receiving node:
- if
node_idis NOT a valid compressed public key:- SHOULD send a
warning. - MAY close the connection.
- MUST NOT process the message further.
- SHOULD send a
- if
signatureis NOT a valid signature (usingnode_idof the double-SHA256 of the entire message following thesignaturefield, including any future fields appended to the end):- SHOULD send a
warning. - MAY close the connection.
- MUST NOT process the message further.
- SHOULD send a
- if
featuresfield contains unknown even bits:- SHOULD NOT connect to the node.
- Unless paying a BOLT #11 invoice which does not have the same bit(s) set, MUST NOT attempt to send payments to the node.
- MUST NOT route a payment through the node.
- SHOULD ignore the first
address descriptorthat does NOT match the types defined above. - if
addrlenis insufficient to hold the address descriptors of the known types:- SHOULD send a
warning. - MAY close the connection.
- SHOULD send a
- if
portis equal to 0:- SHOULD ignore
ipv6_addrORipv4_addrORhostname.
- SHOULD ignore
- if
node_idis NOT previously known from achannel_announcementmessage, OR iftimestampis NOT greater than the last-receivednode_announcementfrom thisnode_id:- SHOULD ignore the message.
- otherwise:
- if
timestampis greater than the last-receivednode_announcementfrom thisnode_id:- SHOULD queue the message for rebroadcasting.
- MAY choose NOT to queue messages longer than the minimum expected length.
- if
- MAY use
rgb_colorANDaliasto reference nodes in interfaces.- SHOULD insinuate their self-signed origins.
- SHOULD ignore Tor v2 onion services.
- if more than one
type 5address is announced:- SHOULD ignore the additional data.
- MUST not forward the
node_announcement.
New node features are possible in the future: backwards compatible (or
optional) ones will have odd feature bits, incompatible ones will have
even feature bits. These will be propagated normally; incompatible
feature bits here refer to the nodes, not the node_announcement message
itself.
New address types may be added in the future; as address descriptors have
to be ordered in ascending order, unknown ones can be safely ignored.
Additional fields beyond addresses may also be added in the future—with
optional padding within addresses, if they require certain alignment.
Node aliases are user-defined and provide a potential avenue for injection attacks, both during the process of rendering and during persistence.
Node aliases should always be sanitized before being displayed in HTML/Javascript contexts or any other dynamically interpreted rendering frameworks. Similarly, consider using prepared statements, input validation, and escaping to protect against injection vulnerabilities and persistence engines that support SQL or other dynamically interpreted querying languages.
Don't be like the school of Little Bobby Tables.
After a channel has been initially announced, each side independently
announces the fees and minimum expiry delta it requires to relay HTLCs
through this channel. Each uses the 8-byte channel shortid that matches the
channel_announcement and the 1-bit channel_flags field to indicate which end of the
channel it's on (origin or final). A node can do this multiple times, in
order to change fees.
Note that the channel_update gossip message is only useful in the context
of relaying payments, not sending payments. When making a payment
A -> B -> C -> D, only the channel_updates related to channels
B -> C (announced by B) and C -> D (announced by C) will
come into play. When building the route, amounts and expiries for HTLCs need
to be calculated backward from the destination to the source. The exact initial
value for amount_msat and the minimal value for cltv_expiry, to be used for
the last HTLC in the route, are provided in the payment request
(see BOLT #11).
- type: 258 (
channel_update) - data:
- [
signature:signature] - [
chain_hash:chain_hash] - [
short_channel_id:short_channel_id] - [
u32:timestamp] - [
byte:message_flags] - [
byte:channel_flags] - [
u16:cltv_expiry_delta] - [
u64:htlc_minimum_msat] - [
u32:fee_base_msat] - [
u32:fee_proportional_millionths] - [
u64:htlc_maximum_msat]
- [
The channel_flags bitfield is used to indicate the direction of the channel: it
identifies the node that this update originated from and signals various options
concerning the channel. The following table specifies the meaning of its
individual bits:
| Bit Position | Name | Meaning |
|---|---|---|
| 0 | direction |
Direction this update refers to. |
| 1 | disable |
Disable the channel. |
The message_flags bitfield is used to provide additional details about the message:
| Bit Position | Name |
|---|---|
| 0 | must_be_one |
| 1 | dont_forward |
The node_id for the signature verification is taken from the corresponding
channel_announcement: node_id_1 if the least-significant bit of flags is 0
or node_id_2 otherwise.
The origin node:
- MUST NOT send a created
channel_updatebeforechannel_readyhas been received. - MAY create a
channel_updateto communicate the channel parameters to the channel peer, even though the channel has not yet been announced (i.e. theannounce_channelbit was not set or thechannel_updateis sent before the peers exchanged announcement signatures).- MUST set the
short_channel_idto either analiasit has received from the peer, or the real channelshort_channel_id. - MUST set
dont_forwardto 1 inmessage_flags - MUST NOT forward such a
channel_updateto other peers, for privacy reasons. - Note: such a
channel_update, one not preceded by achannel_announcement, is invalid to any other peer and would be discarded.
- MUST set the
- MUST set
signatureto the signature of the double-SHA256 of the entire remaining packet aftersignature, using its ownnode_id. - MUST set
chain_hashANDshort_channel_idto match the 32-byte hash AND 8-byte channel ID that uniquely identifies the channel specified in thechannel_announcementmessage. - if the origin node is
node_id_1in the message:- MUST set the
directionbit ofchannel_flagsto 0.
- MUST set the
- otherwise:
- MUST set the
directionbit ofchannel_flagsto 1.
- MUST set the
- MUST set
htlc_maximum_msatto the maximum value it will send through this channel for a single HTLC.- MUST set this to less than or equal to the channel capacity.
- MUST set this to less than or equal to
max_htlc_value_in_flight_msatit received from the peer. - MUST set this to greater than or equal to
htlc_minimum_msat.
- MUST set
must_be_oneinmessage_flagsto 1. - MUST set bits in
channel_flagsandmessage_flagsthat are not assigned a meaning to 0. - MAY create and send a
channel_updatewith thedisablebit set to 1, to signal a channel's temporary unavailability (e.g. due to a loss of connectivity) OR permanent unavailability (e.g. prior to an on-chain settlement).- MAY sent a subsequent
channel_updatewith thedisablebit set to 0 to re-enable the channel.
- MAY sent a subsequent
- MUST set
timestampto greater than 0, AND to greater than any previously-sentchannel_updatefor thisshort_channel_id.- SHOULD base
timestampon a UNIX timestamp.
- SHOULD base
- MUST set
cltv_expiry_deltato the number of blocks it will subtract from an incoming HTLC'scltv_expiry. - MUST set
htlc_minimum_msatto the minimum HTLC value (in millisatoshi) that the channel peer will accept.- MUST set
htlc_minimum_msatto less than or equal tohtlc_maximum_msat.
- MUST set
- MUST set
fee_base_msatto the base fee (in millisatoshi) it will charge for any HTLC. - MUST set
fee_proportional_millionthsto the amount (in millionths of a satoshi) it will charge per transferred satoshi. - SHOULD NOT create redundant
channel_updates - If it creates a new
channel_updatewith updated channel parameters:- SHOULD keep accepting the previous channel parameters for 10 minutes
The receiving node:
- if the
short_channel_iddoes NOT match a previouschannel_announcement, OR if the channel has been closed in the meantime:- MUST ignore
channel_updates that do NOT correspond to one of its own channels.
- MUST ignore
- SHOULD accept
channel_updates for its own channels (even if non-public), in order to learn the associated origin nodes' forwarding parameters. - if
signatureis not a valid signature, usingnode_idof the double-SHA256 of the entire message following thesignaturefield (including unknown fields followingfee_proportional_millionths):- SHOULD send a
warningand close the connection. - MUST NOT process the message further.
- SHOULD send a
- if the specified
chain_hashvalue is unknown (meaning it isn't active on the specified chain):- MUST ignore the channel update.
- if the
timestampis equal to the last-receivedchannel_updatefor thisshort_channel_idANDnode_id:- if the fields below
timestampdiffer:- MAY blacklist this
node_id. - MAY forget all channels associated with it.
- MAY blacklist this
- if the fields below
timestampare equal:- SHOULD ignore this message
- if the fields below
- if
timestampis lower than that of the last-receivedchannel_updatefor thisshort_channel_idAND fornode_id:- SHOULD ignore the message.
- otherwise:
- if the
timestampis unreasonably far in the future:- MAY discard the
channel_update.
- MAY discard the
- otherwise:
- SHOULD queue the message for rebroadcasting.
- MAY choose NOT to for messages longer than the minimum expected length.
- if the
- if
htlc_maximum_msat<htlc_minimum_msat:- SHOULD ignore this channel during route considerations.
- if
htlc_maximum_msatis greater than channel capacity:- MAY blacklist this
node_id - SHOULD ignore this channel during route considerations.
- MAY blacklist this
- otherwise:
- SHOULD consider the
htlc_maximum_msatwhen routing.
- SHOULD consider the
The timestamp field is used by nodes for pruning channel_updates that are
either too far in the future or have not been updated in two weeks; so it
makes sense to have it be a UNIX timestamp (i.e. seconds since UTC
1970-01-01). This cannot be a hard requirement, however, given the possible case
of two channel_updates within a single second.
It is assumed that more than one channel_update message changing the channel
parameters in the same second may be a DoS attempt, and therefore, the node responsible
for signing such messages may be blacklisted. However, a node may send a same
channel_update message with a different signature (changing the nonce in signature
signing), and hence fields apart from signature are checked to see if the channel
parameters have changed for the same timestamp. It is also important to note that
ECDSA signatures are malleable. So, an intermediate node who received the channel_update
message can rebroadcast it just by changing the s component of signature with -s.
This should however not result in the blacklist of the node_id from where
the message originated.
The recommendation against redundant channel_updates minimizes spamming the network,
however it is sometimes inevitable. For example, a channel with a
peer which is unreachable will eventually cause a channel_update to
indicate that the channel is disabled, with another update re-enabling
the channel when the peer reestablishes contact. Because gossip
messages are batched and replace previous ones, the result may be a
single seemingly-redundant update.
When a node creates a new channel_update to change its channel parameters,
it will take some time to propagate through the network and payers may use
older parameters. It is recommended to keep accepting older parameters for
at least 10 minutes to improve payment latency and reliability.
The must_be_one field in message_flags was previously used to indicate
the presence of the htlc_maximum_msat field. This field must now always
be present, so must_be_one is a constant value, and ignored by receivers.
Understanding of messages used to be indicated with the gossip_queries
feature bit; now these messages are universally supported, that feature has
now been slightly repurposed. Not offering this feature means a node is not
worth querying for gossip: either they do not store the entire gossip map, or
they are only connected to a single peer (this one).
There are several messages which contain a long array of
short_channel_ids (called encoded_short_ids) so we include an encoding byte
which allows for different encoding schemes to be defined in the future, if they
provide benefit.
Encoding types:
0: uncompressed array ofshort_channel_idtypes, in ascending order.1: Previously used for zlib compression, this encoding MUST NOT be used.
This encoding is also used for arrays of other types (timestamps, flags, ...),
and specified with an encoded_ prefix. For example, encoded_timestamps is
an array of timestamps with a 0 prefix.
Query messages can be extended with optional fields that can help reduce the number of messages needed to synchronize routing tables by enabling:
- timestamp-based filtering of
channel_updatemessages: only ask forchannel_updatemessages that are newer than the ones you already have. - checksum-based filtering of
channel_updatemessages: only ask forchannel_updatemessages that carry different information from the ones you already have.
Nodes can signal that they support extended gossip queries with the gossip_queries_ex feature bit.
-
type: 261 (
query_short_channel_ids) -
data:
- [
chain_hash:chain_hash] - [
u16:len] - [
len*byte:encoded_short_ids] - [
query_short_channel_ids_tlvs:tlvs]
- [
-
tlv_stream:query_short_channel_ids_tlvs -
types:
- type: 1 (
query_flags) - data:
- [
byte:encoding_type] - [
...*byte:encoded_query_flags]
- [
- type: 1 (
encoded_query_flags is an array of bitfields, one bigsize per bitfield, one bitfield for each short_channel_id. Bits have the following meaning:
| Bit Position | Meaning |
|---|---|
| 0 | Sender wants channel_announcement |
| 1 | Sender wants channel_update for node 1 |
| 2 | Sender wants channel_update for node 2 |
| 3 | Sender wants node_announcement for node 1 |
| 4 | Sender wants node_announcement for node 2 |
Query flags must be minimally encoded, which means that one flag will be encoded with a single byte.
- type: 262 (
reply_short_channel_ids_end) - data:
- [
chain_hash:chain_hash] - [
byte:full_information]
- [
This is a general mechanism which lets a node query for the
channel_announcement and channel_update messages for specific channels
(identified via short_channel_ids). This is usually used either because
a node sees a channel_update for which it has no channel_announcement or
because it has obtained previously unknown short_channel_ids
from reply_channel_range.
The sender:
- SHOULD NOT send this to a peer which does not offer
gossip_queries. - MUST NOT send
query_short_channel_idsif it has sent a previousquery_short_channel_idsto this peer and not receivedreply_short_channel_ids_end. - MUST set
chain_hashto the 32-byte hash that uniquely identifies the chain that theshort_channel_ids refer to. - MUST set the first byte of
encoded_short_idsto the encoding type. - MUST encode a whole number of
short_channel_ids toencoded_short_ids - MAY send this if it receives a
channel_updatefor ashort_channel_idfor which it has nochannel_announcement. - SHOULD NOT send this if the channel referred to is not an unspent output.
- MAY include an optional
query_flags. If so:- MUST set
encoding_type, as forencoded_short_ids. - Each query flag is a minimally-encoded bigsize.
- MUST encode one query flag per
short_channel_id.
- MUST set
The receiver:
- if the first byte of
encoded_short_idsis not a known encoding type:- MAY send a
warning. - MAY close the connection.
- MAY send a
- if
encoded_short_idsdoes not decode into a whole number ofshort_channel_id:- MAY send a
warning. - MAY close the connection.
- MAY send a
- if it has not sent
reply_short_channel_ids_endto a previously receivedquery_short_channel_idsfrom this sender:- MAY send a
warning. - MAY close the connection.
- MAY send a
- if the incoming message includes
query_short_channel_ids_tlvs:- if
encoding_typeis not a known encoding type:- MAY send a
warning. - MAY close the connection.
- MAY send a
- if
encoded_query_flagsdoes not decode to exactly one flag pershort_channel_id:- MAY send a
warning. - MAY close the connection.
- MAY send a
- if
- MUST respond to each known
short_channel_id:- if the incoming message does not include
encoded_query_flags:- with a
channel_announcementand the latestchannel_updatefor each end - MUST follow with any
node_announcements for eachchannel_announcement
- with a
- otherwise:
- We define
query_flagfor the Nthshort_channel_idinencoded_short_idsto be the Nth bigsize of the decodedencoded_query_flags. - if bit 0 of
query_flagis set:- MUST reply with a
channel_announcement
- MUST reply with a
- if bit 1 of
query_flagis set and it has received achannel_updatefromnode_id_1:- MUST reply with the latest
channel_updatefornode_id_1
- MUST reply with the latest
- if bit 2 of
query_flagis set and it has received achannel_updatefromnode_id_2:- MUST reply with the latest
channel_updatefornode_id_2
- MUST reply with the latest
- if bit 3 of
query_flagis set and it has received anode_announcementfromnode_id_1:- MUST reply with the latest
node_announcementfornode_id_1
- MUST reply with the latest
- if bit 4 of
query_flagis set and it has received anode_announcementfromnode_id_2:- MUST reply with the latest
node_announcementfornode_id_2
- MUST reply with the latest
- We define
- SHOULD NOT wait for the next outgoing gossip flush to send these.
- if the incoming message does not include
- SHOULD avoid sending duplicate
node_announcementsin response to a singlequery_short_channel_ids. - MUST follow these responses with
reply_short_channel_ids_end. - if does not maintain up-to-date channel information for
chain_hash:- MUST set
full_informationto 0.
- MUST set
- otherwise:
- SHOULD set
full_informationto 1.
- SHOULD set
Future nodes may not have complete information; they certainly won't have
complete information on unknown chain_hash chains. While this full_information
field (previously and confusingly called complete) cannot be trusted, a 0 does indicate that the sender should search
elsewhere for additional data.
The explicit reply_short_channel_ids_end message means that the receiver can
indicate it doesn't know anything, and the sender doesn't need to rely on
timeouts. It also causes a natural ratelimiting of queries.
-
type: 263 (
query_channel_range) -
data:
- [
chain_hash:chain_hash] - [
u32:first_blocknum] - [
u32:number_of_blocks] - [
query_channel_range_tlvs:tlvs]
- [
-
tlv_stream:query_channel_range_tlvs -
types:
- type: 1 (
query_option) - data:
- [
bigsize:query_option_flags]
- [
- type: 1 (
query_option_flags is a bitfield represented as a minimally-encoded bigsize. Bits have the following meaning:
| Bit Position | Meaning |
|---|---|
| 0 | Sender wants timestamps |
| 1 | Sender wants checksums |
Though it is possible, it would not be very useful to ask for checksums without asking for timestamps too: the receiving node may have an older channel_update with a different checksum, asking for it would be useless. And if a channel_update checksum is actually 0 (which is quite unlikely) it will not be queried.
-
type: 264 (
reply_channel_range) -
data:
- [
chain_hash:chain_hash] - [
u32:first_blocknum] - [
u32:number_of_blocks] - [
byte:sync_complete] - [
u16:len] - [
len*byte:encoded_short_ids] - [
reply_channel_range_tlvs:tlvs]
- [
-
tlv_stream:reply_channel_range_tlvs -
types:
- type: 1 (
timestamps_tlv) - data:
- [
byte:encoding_type] - [
...*byte:encoded_timestamps]
- [
- type: 3 (
checksums_tlv) - data:
- [
...*channel_update_checksums:checksums]
- [
- type: 1 (
For a single channel_update, timestamps are encoded as:
- subtype:
channel_update_timestamps - data:
- [
u32:timestamp_node_id_1] - [
u32:timestamp_node_id_2]
- [
Where:
timestamp_node_id_1is the timestamp of thechannel_updatefornode_id_1, or 0 if there was nochannel_updatefrom that node.timestamp_node_id_2is the timestamp of thechannel_updatefornode_id_2, or 0 if there was nochannel_updatefrom that node.
For a single channel_update, checksums are encoded as:
- subtype:
channel_update_checksums - data:
- [
u32:checksum_node_id_1] - [
u32:checksum_node_id_2]
- [
Where:
checksum_node_id_1is the checksum of thechannel_updatefornode_id_1, or 0 if there was nochannel_updatefrom that node.checksum_node_id_2is the checksum of thechannel_updatefornode_id_2, or 0 if there was nochannel_updatefrom that node.
The checksum of a channel_update is the CRC32C checksum as specified in RFC3720 of this channel_update without its signature and timestamp fields.
This allows querying for channels within specific blocks.
The sender of query_channel_range:
- SHOULD NOT send this to a peer which does not offer
gossip_queries. - MUST NOT send this if it has sent a previous
query_channel_rangeto this peer and not received allreply_channel_rangereplies. - MUST set
chain_hashto the 32-byte hash that uniquely identifies the chain that it wants thereply_channel_rangeto refer to - MUST set
first_blocknumto the first block it wants to know channels for - MUST set
number_of_blocksto 1 or greater. - MAY append an additional
query_channel_range_tlv, which specifies the type of extended information it would like to receive.
The receiver of query_channel_range:
- if it has not sent all
reply_channel_rangeto a previously receivedquery_channel_rangefrom this sender:- MAY send a
warning. - MAY close the connection.
- MAY send a
- MUST respond with one or more
reply_channel_range:- MUST set with
chain_hashequal to that ofquery_channel_range, - MUST limit
number_of_blocksto the maximum number of blocks whose results could fit inencoded_short_ids - MAY split block contents across multiple
reply_channel_range. - the first
reply_channel_rangemessage:- MUST set
first_blocknumless than or equal to thefirst_blocknuminquery_channel_range - MUST set
first_blocknumplusnumber_of_blocksgreater thanfirst_blocknuminquery_channel_range.
- MUST set
- successive
reply_channel_rangemessage:- MUST have
first_blocknumequal or greater than the previousfirst_blocknum.
- MUST have
- MUST set
sync_completetofalseif this is not the finalreply_channel_range. - the final
reply_channel_rangemessage:- MUST have
first_blocknumplusnumber_of_blocksequal or greater than thequery_channel_rangefirst_blocknumplusnumber_of_blocks.
- MUST have
- MUST set
sync_completetotrue.
- MUST set with
If the incoming message includes query_option, the receiver MAY append additional information to its reply:
- if bit 0 in
query_option_flagsis set, the receiver MAY append atimestamps_tlvthat containschannel_updatetimestamps for allshort_channel_ids inencoded_short_ids - if bit 1 in
query_option_flagsis set, the receiver MAY append achecksums_tlvthat containschannel_updatechecksums for allshort_channel_ids inencoded_short_ids
A single response might be too large for a single packet, so multiple replies may be required. We want to allow a peer to store canned results for (say) 1000-block ranges, so replies can exceed the requested range. However, we require that each reply be relevant (overlapping the requested range).
By insisting that replies be in increasing order, the receiver can easily
determine if replies are done: simply check if first_blocknum plus
number_of_blocks equals or exceeds the first_blocknum plus
number_of_blocks it asked for.
The addition of timestamp and checksum fields allow a peer to omit querying for redundant updates.
- type: 265 (
gossip_timestamp_filter) - data:
- [
chain_hash:chain_hash] - [
u32:first_timestamp] - [
u32:timestamp_range]
- [
This message allows a node to constrain future gossip messages to a specific range. A node which wants any gossip messages has to send this, otherwise no gossip messages would be received.
Note that this filter replaces any previous one, so it can be used multiple times to change the gossip from a peer.
The sender:
- MUST set
chain_hashto the 32-byte hash that uniquely identifies the chain that it wants the gossip to refer to. - If the receiver does not offer
gossip_queries:- SHOULD set
first_timestampto 0xFFFFFFFF andtimestamp_rangeto 0.
- SHOULD set
The receiver:
- SHOULD send all gossip messages whose
timestampis greater or equal tofirst_timestamp, and less thanfirst_timestampplustimestamp_range.- MAY wait for the next outgoing gossip flush to send these.
- SHOULD send gossip messages as it generates them regardless of
timestamp. - Otherwise (relayed gossip):
- SHOULD restrict future gossip messages to those whose
timestampis greater or equal tofirst_timestamp, and less thanfirst_timestampplustimestamp_range.
- SHOULD restrict future gossip messages to those whose
- If a
channel_announcementhas no correspondingchannel_updates:- MUST NOT send the
channel_announcement.
- MUST NOT send the
- Otherwise:
- MUST consider the
timestampof thechannel_announcementto be thetimestampof a correspondingchannel_update. - MUST consider whether to send the
channel_announcementafter receiving the first correspondingchannel_update.
- MUST consider the
- If a
channel_announcementis sent:- MUST send the
channel_announcementprior to any correspondingchannel_updates andnode_announcements.
- MUST send the
Since channel_announcement doesn't have a timestamp, we generate a likely
one. If there's no channel_update then it is not sent at all, which is most
likely in the case of pruned channels.
Otherwise the channel_announcement is usually followed immediately by a
channel_update. Ideally we would specify that the first (oldest) channel_update's
timestamp is to be used as the time of the channel_announcement, but new nodes on
the network will not have this, and further would require the first channel_update
timestamp to be stored. Instead, we allow any update to be used, which
is simple to implement.
In the case where the channel_announcement is nonetheless missed,
query_short_channel_ids can be used to retrieve it.
Nodes can use timestamp_filter to reduce their gossip load when they
have many peers (eg. setting first_timestamp to 0xFFFFFFFF after the
first few peers, in the assumption that propagation is adequate).
This assumption of adequate propagation does not apply for gossip messages
generated directly by the node itself, so they should ignore filters.
A node:
- MUST NOT relay any gossip messages it did not generate itself, unless explicitly requested.
A receiving node:
- upon receiving a new
channel_announcementor achannel_updateornode_announcementwith an updatedtimestamp:- SHOULD update its local view of the network's topology accordingly.
- after applying the changes from the announcement:
- if there are no channels associated with the corresponding origin node:
- MAY purge the origin node from its set of known nodes.
- otherwise:
- SHOULD update the appropriate metadata AND store the signature
associated with the announcement.
- Note: this will later allow the node to rebuild the announcement for its peers.
- SHOULD update the appropriate metadata AND store the signature
associated with the announcement.
- if there are no channels associated with the corresponding origin node:
A node:
- MUST not send gossip it did not generate itself, until it receives
gossip_timestamp_filter. - SHOULD flush outgoing gossip messages once every 60 seconds, independently of
the arrival times of the messages.
- Note: this results in staggered announcements that are unique (not duplicated).
- SHOULD NOT forward gossip messages to peers who sent
networksininitand did not specify thechain_hashof this gossip message.
- MAY re-announce its channels regularly.
- Note: this is discouraged, in order to keep the resource requirements low.
Once the gossip message has been processed, it's added to a list of outgoing messages, destined for the processing node's peers, replacing any older updates from the origin node. This list of gossip messages will be flushed at regular intervals; such a store-and-delayed-forward broadcast is called a staggered broadcast. Also, such batching forms a natural rate limit with low overhead.
The origin node:
- SHOULD accept HTLCs that pay a fee equal to or greater than:
- fee_base_msat + ( amount_to_forward * fee_proportional_millionths / 1000000 )
- SHOULD accept HTLCs that pay an older fee, for some reasonable time after
sending
channel_update.- Note: this allows for any propagation delay.
A node:
- SHOULD monitor the funding transactions in the blockchain, to identify channels that are being closed.
- if the funding output of a channel is spent and received 12 block confirmations:
- SHOULD be removed from the local network view AND be considered closed.
- if the announced node no longer has any associated open channels:
- MAY prune nodes added through
node_announcementmessages from their local view.- Note: this is a direct result of the dependency of a
node_announcementbeing preceded by achannel_announcement.
- Note: this is a direct result of the dependency of a
- MAY prune nodes added through
A node:
- if the
timestampof the latestchannel_updatein either direction is older than two weeks (1209600 seconds):- MAY prune the channel.
- MAY ignore the channel.
- Note: this is an individual node policy and MUST NOT be enforced by forwarding peers, e.g. by closing channels when receiving outdated gossip messages.
Several scenarios may result in channels becoming unusable and its endpoints
becoming unable to send updates for these channels. For example, this occurs if
both endpoints lose access to their private keys and can neither sign
channel_updates nor close the channel on-chain. In this case, the channels are
unlikely to be part of a computed route, since they would be partitioned off
from the rest of the network; however, they would remain in the local network
view would be forwarded to other peers indefinitely.
The oldest channel_update is used to prune the channel since both sides need
to be active in order for the channel to be usable. Doing so prunes channels
even if one side continues to send fresh channel_updates but the other node
has disappeared.
When calculating a route for an HTLC, both the cltv_expiry_delta and the fee
need to be considered: the cltv_expiry_delta contributes to the time that
funds will be unavailable in the event of a worst-case failure. The relationship
between these two attributes is unclear, as it depends on the reliability of the
nodes involved.
If a route is computed by simply routing to the intended recipient and summing
the cltv_expiry_deltas, then it's possible for intermediate nodes to guess
their position in the route. Knowing the CLTV of the HTLC, the surrounding
network topology, and the cltv_expiry_deltas gives an attacker a way to guess
the intended recipient. Therefore, it's highly desirable to add a random offset
to the CLTV that the intended recipient will receive, which bumps all CLTVs
along the route.
In order to create a plausible offset, the origin node MAY start a limited
random walk on the graph, starting from the intended recipient and summing the
cltv_expiry_deltas, and use the resulting sum as the offset.
This effectively creates a shadow route extension to the actual route and
provides better protection against this attack vector than simply picking a
random offset would.
Other more advanced considerations involve diversification of route selection, to avoid single points of failure and detection, and balancing of local channels.
Consider four nodes:
B
/ \
/ \
A C
\ /
\ /
D
Each advertises the following cltv_expiry_delta on its end of every
channel:
- A: 10 blocks
- B: 20 blocks
- C: 30 blocks
- D: 40 blocks
C also uses a min_final_cltv_expiry_delta of 18 (the default) when requesting
payments.
Also, each node has a set fee scheme that it uses for each of its channels:
- A: 100 base + 1000 millionths
- B: 200 base + 2000 millionths
- C: 300 base + 3000 millionths
- D: 400 base + 4000 millionths
The network will see eight channel_update messages:
- A->B:
cltv_expiry_delta= 10,fee_base_msat= 100,fee_proportional_millionths= 1000 - A->D:
cltv_expiry_delta= 10,fee_base_msat= 100,fee_proportional_millionths= 1000 - B->A:
cltv_expiry_delta= 20,fee_base_msat= 200,fee_proportional_millionths= 2000 - D->A:
cltv_expiry_delta= 40,fee_base_msat= 400,fee_proportional_millionths= 4000 - B->C:
cltv_expiry_delta= 20,fee_base_msat= 200,fee_proportional_millionths= 2000 - D->C:
cltv_expiry_delta= 40,fee_base_msat= 400,fee_proportional_millionths= 4000 - C->B:
cltv_expiry_delta= 30,fee_base_msat= 300,fee_proportional_millionths= 3000 - C->D:
cltv_expiry_delta= 30,fee_base_msat= 300,fee_proportional_millionths= 3000
B->C. If B were to send 4,999,999 millisatoshi directly to C, it would
neither charge itself a fee nor add its own cltv_expiry_delta, so it would
use C's requested min_final_cltv_expiry_delta of 18. Presumably it would also add a
shadow route to give an extra CLTV of 42. Additionally, it could add extra
CLTV deltas at other hops, as these values represent a minimum, but chooses not
to do so here, for the sake of simplicity:
amount_msat: 4999999cltv_expiry: current-block-height + 18 + 42onion_routing_packet:amt_to_forward= 4999999outgoing_cltv_value= current-block-height + 18 + 42
A->B->C. If A were to send 4,999,999 millisatoshi to C via B, it needs to
pay B the fee it specified in the B->C channel_update, calculated as
per HTLC Fees:
fee_base_msat + ( amount_to_forward * fee_proportional_millionths / 1000000 )
200 + ( 4999999 * 2000 / 1000000 ) = 10199
Similarly, it would need to add B->C's channel_update cltv_expiry_delta (20), C's
requested min_final_cltv_expiry_delta (18), and the cost for the shadow route (42).
Thus, A->B's update_add_htlc message would be:
amount_msat: 5010198cltv_expiry: current-block-height + 20 + 18 + 42onion_routing_packet:amt_to_forward= 4999999outgoing_cltv_value= current-block-height + 18 + 42
B->C's update_add_htlc would be the same as B->C's direct payment above.
A->D->C. Finally, if for some reason A chose the more expensive route via D,
A->D's update_add_htlc message would be:
amount_msat: 5020398cltv_expiry: current-block-height + 40 + 18 + 42onion_routing_packet:amt_to_forward= 4999999outgoing_cltv_value= current-block-height + 18 + 42
And D->C's update_add_htlc would again be the same as B->C's direct payment
above.

This work is licensed under a Creative Commons Attribution 4.0 International License.