mirror of
https://github.com/lnbook/lnbook
synced 2024-11-18 21:28:03 +00:00
656 lines
31 KiB
Plaintext
656 lines
31 KiB
Plaintext
# Channel Graph Discovery, Authentication & Maintenance
|
|
|
|
## Intro
|
|
|
|
In this chapter, we'll explore exactly _how_ Lightning nodes discover each
|
|
other, and also the channel graph itself. The channel graph is the
|
|
interconnected set of publicly advertised channels (more on that later), and
|
|
the nodes that these channels interlink. When most refer to the _network_ part
|
|
of the Lightning Network, they're referring to the Channel Graph which itself
|
|
is a unique authenticated data structured _anchored_ in the base Bitcoin
|
|
blockchain.
|
|
|
|
As the Lightning Network is a peer-to-peer network, some initial bootstrapping
|
|
is required in order for peers to discover each other. Within this chapter
|
|
we'll follow the story of a new peer connecting to the network for the first
|
|
time, and examine each step in the bootstrapping process from initial peer
|
|
discovery, to channel graph syncing and validation.
|
|
|
|
As an initial step, our new node needs to somehow _discover_ at least _one_
|
|
peer that is already connected to the network and has a full channel graph (as
|
|
we'll see later, there's no canonical version as the update dissemination
|
|
system is _eventually consistent_). Using on of many initial bootstrapping
|
|
protocols to find that first peer, after a connection is established, our new
|
|
peer now needs to _download_ and _validate_ the channel graph. Once the channel
|
|
graph has been fully validated, our new peer is ready to start opening channels
|
|
and sending payments on the network.
|
|
|
|
After initial bootstrap, a node on the network needs to continue to maintain
|
|
its view of the channel graph by: processing new channel routing policy
|
|
updates, discovering and validating new channels, removing channels that have
|
|
been closed on chain, and finally pruning channels that fail to send out a
|
|
proper "heartbeat" every 2 weeks or so.
|
|
|
|
Upon completion of this chapter, the reader will understand a key component of
|
|
the p2p Lightning Network: namely how peers discover each other and maintain a
|
|
personal view of the channel graph. We'll being our story with exploring the
|
|
story of a new node that has just booted up, and needs to find other peers to
|
|
connect to on the network.
|
|
|
|
## Peer Discovery
|
|
|
|
In this section, we'll begin to follow the story of Norman, a new Lightning
|
|
node that wishes to join the network as he sets out on his journey to:
|
|
discovery a set of bootstrap peers, download and validate the channel graph,
|
|
and finally begin the process of ongoing maintain once of the channel graph
|
|
itself.
|
|
|
|
|
|
### P2P Boostrapping
|
|
|
|
Before doing any thing else, Norman first needs to discover a set of peers whom
|
|
are already part of the network. We call this process initial peer
|
|
bootstrapping, and it's something hat every peer to peer network needs to
|
|
implement properly in order to ensure a robust, healthy network. Bootstrapping
|
|
new peers to existing peer to peer networks is a very well studied problem with
|
|
several known solutions, each with their own distinct trade offs. The simplest
|
|
solution to this problem is simply to package a set of _hard coded_ bootstrap
|
|
peers into the packaged p2p node software. This is simple in that each new node
|
|
can find the bootstrap peer with nothing else but the software they're running,
|
|
but rather fragile given that if the set of bootstrap peers goes offline, then
|
|
no new nodes will be able to join the network. Due to this fragility, this
|
|
option is usually used as a fallback in case none of the other p2p bootstrapping
|
|
mechanisms work properly.
|
|
|
|
Rather than hard coding the set of bootstrap peers within the software/binary
|
|
itself, we can instead opt to devise a method that allows peers to dynamically
|
|
obtain a fresh/new set of bootstrap peers they can use to join the network.
|
|
We'll call this process initial peer discovery. Typically we'll leverage
|
|
existing Internet protocols to maintain and distribute a set of bootstrapping
|
|
peers. A non-exhaustive list of protocols that have been used in the past to
|
|
accomplish initial peer discovery include:
|
|
|
|
* DNS
|
|
* IRC
|
|
* HTTP
|
|
|
|
Similar to the Bitcoin protocol, the primary initial peer discovery mechanism
|
|
used in the Lightning Network happens via DNS. As initial peer discovery is a critical and
|
|
universal task for the network, the process has been _standardized_ in a
|
|
document that is a part of the Basis of Lightning Technology (BOLT)
|
|
specification. This document is [BOLT
|
|
10](https://github.com/lightningnetwork/lightning-rfc/blob/master/10-dns-bootstrap.md).
|
|
|
|
### DNS Bootstrapping via BOLT 10
|
|
|
|
The BOLT 10 document describes a standardized way of implementing peer
|
|
discovery using the Domain Name System (DNS). Lightning's flavor of DNS based
|
|
bootstrapping uses up to 3 distinct record types:
|
|
|
|
* `SRV` records for discovering a set of _node public keys_.
|
|
* `A` records for mapping a node's public key to its current `IPv4` address.
|
|
* `AAA` records for mapping a node's public key to its current `IPv6` address
|
|
(if one exists).
|
|
|
|
Those somewhat familiar with the DNS protocol may already be familiar with the
|
|
`A` and `AAA` record types, but not the `SRV` type. The `SRV` record type is
|
|
used less commonly by protocols built on DNS, that's used to determine the
|
|
_location_ for a specified service. In our context, the service in question is
|
|
a given Lightning node, and the location its IP address. We need to use this
|
|
additional record type as unlike nodes within the Bitcoin protocol, we need
|
|
both a public key _and_ an IP address in order to connect to a node. As we saw
|
|
in chapter XX on the transport encryption protocol used in LN, by requiring
|
|
knowledge of the public key of a node before one can connect to it, we're able
|
|
to implement a form of _identity_ hiding for nodes in the network.
|
|
|
|
// TODO(roasbeef): move paragraph below above?
|
|
|
|
#### A New Peer's Bootstrapping Workflow
|
|
|
|
Before diving into the specifics of BOLT 10, we'll first outline the high level
|
|
flow of a new node that wishes to use BOLT 10 to join the network.
|
|
|
|
First, a node needs to identify a single, or set of DNS servers that understand
|
|
BOLT 10 so they can be used for p2p bootstrapping. There exists no "official"
|
|
set of DNS seeds for this purpose, but each of the major implementations
|
|
maintain their own DNS seed, and cross query each other's seeds for redundancy
|
|
purposes. DNS seeds exist for both Bitcoin's mainnet and testnet. For the sake
|
|
of our example, we'll assume the existence of a valid BOLT 10 DNS seed at
|
|
`nodes.lightning.directory`.
|
|
|
|
Next, we'll now issue an `SRV` query to obtain a set of _candidate bootstrap
|
|
peers_. The response to our query will be a series of _bech32_ encoded public
|
|
keys. As DNS is a text based protocol, we can't send raw bytes, so an encoding
|
|
scheme is required. For this scheme BOLT 10 has selected _bech32_ due to its
|
|
existing propagation in the wider Bitcoin ecosystem. The number of encoded
|
|
public keys returned depends on the server returning the query, as well as all
|
|
the resolver that stand between the client and the authoritative server. Many
|
|
resolvers may filter out SRV records all together, or attempt to truncate the
|
|
response size itself.
|
|
|
|
Using the widely available `dig` command-line tool, we can query the _testnet_
|
|
version of the DNS seed mentioned above with the following command:
|
|
```
|
|
$ dig @8.8.8.8 test.nodes.lightning.directory SRV
|
|
```
|
|
|
|
We use the `@` argument to force resolution via Google's nameserver as they
|
|
permit our larger SRV query responses. At the end, we specify that we only want
|
|
`SRV` records to be returned. A sample response looks something like:
|
|
```
|
|
$ dig @8.8.8.8 test.nodes.lightning.directory SRV
|
|
|
|
; <<>> DiG 9.10.6 <<>> @8.8.8.8 test.nodes.lightning.directory SRV
|
|
; (1 server found)
|
|
;; global options: +cmd
|
|
;; Got answer:
|
|
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43610
|
|
;; flags: qr rd ra; QUERY: 1, ANSWER: 25, AUTHORITY: 0, ADDITIONAL: 1
|
|
|
|
;; OPT PSEUDOSECTION:
|
|
; EDNS: version: 0, flags:; udp: 512
|
|
;; QUESTION SECTION:
|
|
;test.nodes.lightning.directory. IN SRV
|
|
|
|
;; ANSWER SECTION:
|
|
test.nodes.lightning.directory. 59 IN SRV 10 10 9735 ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7.test.nodes.lightning.directory.
|
|
test.nodes.lightning.directory. 59 IN SRV 10 10 15735 ln1qtgsl3efj8verd4z27k44xu0a59kncvsarxatahm334exgnuvwhnz8dkhx8.test.nodes.lightning.directory.
|
|
|
|
<SNIP>
|
|
|
|
;; Query time: 89 msec
|
|
;; SERVER: 8.8.8.8#53(8.8.8.8)
|
|
;; WHEN: Thu Dec 31 16:41:07 PST 2020
|
|
```
|
|
|
|
We've truncated the response for brevity. In our truncated responses, we can
|
|
see two responses. Starting from the right-most column, we have a candidate
|
|
"virtual" domain name for a target node, then to the left we have the _port_
|
|
that this node can be reached using. The first response uses the standard port
|
|
for LN: `9735`. The second response uses a custom port which is permitted by
|
|
the protocol.
|
|
|
|
Next, we'll attempt to obtain the other piece of information we need to connect
|
|
to a node: it's IP address. Before we can query for this however, we'll fist
|
|
_decode_ the returned sub-domain for this virtual host name returned by the
|
|
server. To do that, we'll first encoded public key:
|
|
```
|
|
ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7
|
|
```
|
|
|
|
Using `bech32`, we can decode this public key to obtain the following valid
|
|
`secp256k1` public key:
|
|
```
|
|
026c64f5a7f24c6f7f0e1d6ec877f23b2f672fb48967c2545f227d70636395eaf3
|
|
```
|
|
|
|
Now that we have the raw public key, we'll now ask the DNS server to _resolve_
|
|
the virtual host given so we can obtain the IP information for the node:
|
|
```
|
|
$ dig ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7.test.nodes.lightning.directory A
|
|
|
|
; <<>> DiG 9.10.6 <<>> ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7.test.nodes.lightning.directory A
|
|
;; global options: +cmd
|
|
;; Got answer:
|
|
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41934
|
|
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
|
|
|
|
;; OPT PSEUDOSECTION:
|
|
; EDNS: version: 0, flags:; udp: 4096
|
|
;; QUESTION SECTION:
|
|
;ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7.test.nodes.lightning.directory. IN A
|
|
|
|
;; ANSWER SECTION:
|
|
ln1qfkxfad87fxx7lcwr4hvsalj8vhkwta539nuy4zlyf7hqcmrjh40xx5frs7.test.nodes.lightning.directory. 60 IN A X.X.X.X
|
|
|
|
;; Query time: 83 msec
|
|
;; SERVER: 2600:1700:6971:6dd0::1#53(2600:1700:6971:6dd0::1)
|
|
;; WHEN: Thu Dec 31 16:59:22 PST 2020
|
|
;; MSG SIZE rcvd: 138
|
|
```
|
|
|
|
In the above command, we've queried the server so we can obtain an `IPv4`
|
|
address for our target node. Now that we have both the raw public key _and_ IP
|
|
address, we can connect to the node using the `brontide` transport protocol at:
|
|
`026c64f5a7f24c6f7f0e1d6ec877f23b2f672fb48967c2545f227d70636395eaf3@X.X.X.X`.
|
|
Querying for the curent `A` record for a given node can also be used to look up
|
|
the _latest_ set of addresses for a given node. Such queries can be used to
|
|
more quickly (compared to waiting on gossip as we'll cover later) sync the
|
|
latest addressing information for a node.
|
|
|
|
At this point in our journey, Norman our new Lightning Node has found its first
|
|
peer and established its first connect! Now we can being the second phase of
|
|
new peer bootstrapping: channel graph synchronization and validation, but
|
|
first, we'll explore more of the intricacies of BOLT 10 itself to take a deeper
|
|
look into how things work under the hood.
|
|
|
|
### A Deep Dive Into BOLT 10
|
|
|
|
As we learned earlier in the chapter, BOLT 10 describes the standardized
|
|
protocol for boostrapping new peer suing the DNS protocol. In this section,
|
|
we'll dive into the details of BOLT 10 itself in order to explore exactly how
|
|
bootstrapping queries are made, and also the additional set of options
|
|
available for querying.
|
|
|
|
#### SRV Query Options
|
|
|
|
The BOLT 10 standard is highly extensible due to its usage of nested
|
|
sub-domains as a communication layer for additional query options. The
|
|
bootstrapping protocol allows clients to further specify the _type_ of nodes
|
|
they're attempting to query for vs the default of receiving a random subset of
|
|
nodes in the query responses.
|
|
|
|
The query option sub-domain scheme uses a series of key-value pairs where the
|
|
key itself is a _single letter_ and the remaining set of text is the value
|
|
itself. The following query types exist in the current version of the BOLT 10
|
|
standards document:
|
|
|
|
* `r`: The "realm" byte which is used to determine which chain or realm
|
|
queries should be returned for. As is, the only value for this key is `0`
|
|
which denotes Bitcoin itself.
|
|
|
|
* `a`: Allows clients to filter out returned nodes based on the _types_ of
|
|
addresses they advertise. As an example, this can be used to only obtain
|
|
nodes that advertise a valid IPv6 address.
|
|
* The value that follows this type is based on a bitfled that _indexes_
|
|
into the set of specified address _type_ which are defined in BOLT 7.
|
|
We'll cover this material shortly later in this chapter once we examine
|
|
the structure of the channel graph itself.
|
|
* The default value for this field is `6`, which is `2 || 4`, which denotes
|
|
bit 1 and 2, which are IPv4 and IPv6.
|
|
|
|
* `l`: A valid node public key serialized in compressed format. This allows a
|
|
client to query for a specified node rather than receiving a set of random
|
|
nodes.
|
|
|
|
* `n`: The number of records to return. The default value for this field is
|
|
`25`.
|
|
|
|
An example query with additional query options looks something like the following:
|
|
```
|
|
r0.a2.n10.nodes.lightning.directory
|
|
```
|
|
|
|
Breaking down the query one key-value pair at a time we gain the following
|
|
insights:
|
|
|
|
* `r0`: The query targets the Bitcoin realm.
|
|
* `a2`: The query only wants IPv4 addresses to be returned.
|
|
* `n10`: The query requests
|
|
|
|
## Channel Graph: Structure and Attributes
|
|
|
|
Now that Norman is able to use the DNS boostrapping protocol to connect to his
|
|
very first peer, we can now start to sync the channel graph! However, before we
|
|
sync the channel graph, we'll need to learn exactly _what_ we mean by the
|
|
channel graph. In this section we'll explore the precise _structure_ of the
|
|
channel graph and examine the unique aspects of the channel graph compared to
|
|
the typical abstract "graph" data structure which is well known/used in the
|
|
field of Computer Science.
|
|
|
|
### The Channel Graph as a Directed Overlay Data Structure
|
|
|
|
A graph in computer science is a special data structure composed of vertices
|
|
(typically referred to as nodes) and edges (also known as links). Two nodes may
|
|
be connected by one or more edges. The channel graph is also _directed_ given
|
|
that a payment is able to flow in either direction over a given edge (a
|
|
channel). As we're concerned with _routing payments_, in our model a node with
|
|
no edges isn't considered to be a part of the graph as it isn't "productive".
|
|
In the context of the Lightning Network, our vertices are the Lightning nodes
|
|
themselves, with our edges being the channels that _connect_ these nodes. As
|
|
channels are themselves a special type of multi-sig UTXO anchored in the base
|
|
Bitcoin blockchain, possible to scan the chain (with the assistance of special
|
|
meta data proofs) and re-derive the channel graph first-hand (though we'd be
|
|
missing some information as we see below).
|
|
|
|
As channels themselves are UTXOs, we can view the channel graph as a special
|
|
sub-set of the UTXO set, on top of which we can add some additional information
|
|
(the nodes, etc) to arrive at the final overlay structure which is the channel
|
|
graph. This anchoring of fundamental components of the cahnnel graph in the
|
|
base Bitcoin blockchain means that it's impossible to _fake_ a valid channel
|
|
graph, which has useful properties when it comes to spam prevention as we'll
|
|
see later. The channel graph in the Lightning Network is composed of 3
|
|
individual components which are described in BOLT 7:
|
|
|
|
* `node_announcement`: The vertex in our graph which communicates the public
|
|
key of a node, as well as how to reach the node over the internet and some
|
|
additional metadata describing the set of _features_ the node supports.
|
|
|
|
* `channel_announcement`: A blockchain anchored proof of the existence of a
|
|
channel between two individual nodes. Any 3rd party can verify this proof in
|
|
order to ensure that a _real_ channel is actually being advertised. Similar
|
|
to the `node_announcement` this message also contains information describing
|
|
the _capabilities_ of the channel which is useful when attempting to route a
|
|
payment.
|
|
|
|
* `channel_update`: A _pair_ of structures that describes the set of _routing
|
|
policies_ for a given channel. `channel_update`s come in a _pair_ as a
|
|
channel is a directed edge, so both sides of the channel are able to specify
|
|
their own custom routing policy. An example of a policy communicated in a
|
|
|
|
It's important to note that each of components of the channel graph are
|
|
themselves _authenticated_ allowing a 3rd party to ensure that the owner of a
|
|
channel/update/node is actually the one sending out an update. This effectively
|
|
makes the Channel Graph a unique type of _authenticated data structure_ that
|
|
cannot be counterfeited. For authentication, we use an `secp256k1` ECDSA
|
|
digital signature (or a series of them) over the serialized digest of the
|
|
message itself. We won't get into the specific of the messaging
|
|
framing/serialization used in the LN in this chapter, as we'll cover that
|
|
information in Chapter XX on the wire protocol used in in the protocol.
|
|
|
|
With the high level structure of the channel graph laid out, we'll now dive
|
|
down into the precise structure of each of the 3 components of the channel
|
|
graph. We'll also explain how one can also _verify_ each component of the
|
|
channel graph as well.
|
|
|
|
#### Node Announcement: Structure & Validation
|
|
|
|
First, we have the `node_announcement` which plays the role of the vertex in
|
|
the channel graph. A node's announcement in the network serves to primary
|
|
purposes:
|
|
|
|
1. To advertise connection information so other nodes can connect to it,
|
|
either to bootstrap to the network, or to attempt to establish a set of new
|
|
channels.
|
|
|
|
2. To communicate the set of features protocol level features a node
|
|
understands. This communication is critical to the decentralized
|
|
de-synchronized update nature of the Lightning Network itself.
|
|
|
|
Unlike channel announcements, node announcements aren't actually anchored in
|
|
the base blockchain. As a result, advertising a node announcement in isolation
|
|
bares no up front cost. As a result, we require that all node announcements are
|
|
only considered "valid" if it has propagated with a corresponding channel
|
|
announcement as well. In other words, we always reject unconnected nodes in
|
|
order to ensure a rogue peer can't fill up our disk with bogus nodes that may
|
|
not actually be part of the network.
|
|
|
|
##### Structure
|
|
|
|
The node announcement is a simple data structure that needs to exist for each
|
|
node that's a part of the channel graph. The node announcement is comprised of
|
|
the following fields, which are encoded using the wire protocol structure
|
|
described in BOLT 1:
|
|
|
|
* `signature`: A valid ECDSA signature that covers the serialized digest of
|
|
all fields listed below. This signature MUST be venerated by the private
|
|
key that backs the public key of the advertised node.
|
|
|
|
* `features`: A bit vector that describes the set of protocol features that
|
|
this node understands. We'll cover this field in more detail in Chapter XX
|
|
on the extensibility of the Lightning Protocol. At a high level, this field
|
|
carries a set of bits (assigned in pairs) that describes which new features
|
|
a node understands. As an example, a node may signal that it understands
|
|
the latest and greatest channel type, which allows peers that which
|
|
bootstrap to the network to filter out the set of nodes they want to connect
|
|
to.
|
|
|
|
* `timestamp`: A timestamp which should be interpreted as a unix epoch
|
|
formatted timestamp. This allows clients to enforce a partial ordering over
|
|
the updates to a node's announcement.
|
|
|
|
* `node_id`: The `secp256k1` public key that this node announcement belongs
|
|
to. There can only be a single `node_announcement` for a given node in the
|
|
channel graph at any given time. As a result, a `node_announcement` can
|
|
superseded a prior `node_announcement` for the same node if it carries a
|
|
higher time stamp.
|
|
|
|
* `rgb_color`: A mostly unused field that allows a node to specify an RGB
|
|
"color" to be associated with it.
|
|
|
|
* `alias`: A UTF-8 string to serve as the nickname for a given node. Note
|
|
that these aliases aren't required to be globally unique, nor are they
|
|
verified in any shape or form. As a result, they are always to be
|
|
interpreted as being "unofficial".
|
|
|
|
* `addresses`: A set of public internet reachable addresses that are to be
|
|
associated with a given node. In the current version of the protocol 4
|
|
address types are supported: IPv4 (1), IPv6 (2), Tor V2 (3), Tor V3 (4). On
|
|
the wire, each of these address types are denoted by an integer type which
|
|
is included in parenthesis after the address type.
|
|
|
|
##### Validation
|
|
|
|
Validating an incoming `node_announcement` is straight forward, the following
|
|
assertions should be upheld when examining a node announcement:
|
|
|
|
* If an existing `node_announcement` for that node is already known, then the
|
|
`timestamp` field of a new incoming `node_announcement` MUST be greater
|
|
than the prior one.
|
|
|
|
* With this constraint, we enforce a forced level of "freshness".
|
|
|
|
* If no `node_announcement` exist for the given node, then an existing
|
|
`channel_announcement` that refernces the given node (more on that later)
|
|
MUST already exist in one's local channel graph.
|
|
|
|
* The included `signature` MUST be a valid ECDSA signature verified using the
|
|
included `node_id` public key and the double-sha256 digest of the raw
|
|
message encoding (mins the signature and frame header!) as the message.
|
|
|
|
* All included `addresses` MUST be sorted in ascending order based on their
|
|
address identifier.
|
|
|
|
* The included `alias` bytes MUST be a valid UTF-8 string.
|
|
|
|
#### Channel Announcement: Structure & Validation
|
|
|
|
Next, we have the `channel_announcement`. This message is used to _announce_ a
|
|
new _public_ channel to the wider network. Note that announcing a channel is
|
|
_optional_. A channel only needs to be announced if its intended to be used for
|
|
routing by the public network. Active routing nodes may wish to announce all
|
|
their channels. However, certain nodes like mobile nodes likely don't have the
|
|
uptime or desire required to be an active routing node. As a result, these
|
|
mobile nodes (which typically use light clients to connect to the Bitcoin p2p
|
|
network), instead may have purely _unadvertised_ channels.
|
|
|
|
##### Unadvertised Channels & The "True" Channel Graph
|
|
|
|
An unadvertised channel isn't part of the known public channel graph, but can
|
|
still be used to send/receive payments. An astute reader may now be wondering
|
|
how a channel which isn't part of the public channel graph is able to receive
|
|
payments. The solution to this problem is a set of "path finding helpers" that
|
|
we call "routing hints. As we'll see in Chapter XX on the presentation/payment
|
|
layer, invoices created by nodes with unadvertised channels will include
|
|
auxiliary information to help the sender route to them assuming the no has at
|
|
least a single channel with an existing public routing node.
|
|
|
|
Due to the existence of unadvertised channels, the _true_ size of the channel
|
|
graph (both the public and private components) is unknown. In addition, any
|
|
snapshot of the channel graph that doesn't come directly from one's own node
|
|
(via a Block Explorer or the like) is to be considered non-canonical as
|
|
updates to the graph are communicated using a system that only is able to
|
|
achieve an eventually consistent view of the channel graph.
|
|
|
|
##### Locating Channel In the Blockchain via Short Channel IDs
|
|
|
|
As mentioned earlier, the channel graph is authenticated due to its usage of
|
|
public key cryptography, as well as the Bitcoin blockchain as a spam prevention
|
|
system. In order to have a node accept a new `channel_announcement`, the
|
|
advertise must _prove_ that the channel actually exists in the Bitcoin
|
|
blockchain. This proof system adds an upfront cost to adding a new entry to the
|
|
channel graph (the on-chain fees on must pay to create the UTXO of the
|
|
channel). As a result, we mitigate spam and ensure that another node on the
|
|
network can't costless fill up the disk of an honest node with bogus channels.
|
|
|
|
Given that we need to construct a proof of the existence of a channel, a
|
|
natural question that arises is: how to we "point to" or reference a given
|
|
channel for the verifier? Given that a channel MUST be a UTXO, an initial
|
|
thought might be to first attempt to just advertise the full outpoint
|
|
(`txid:index`) of the channel. Given the outpoint of a UTXO is globally unique
|
|
one confirmed in the chain, this sounds like a good idea, however it has one
|
|
fatal flow: the verifier must maintain a full copy of the UTXO set in order to
|
|
verify channels. This works fine for full-node, but light clients which rely on
|
|
primarily PoW verification don't typically maintain a full UTXO set. As we want
|
|
to ensure we can support mobile nodes in the Lightning Network, we're forced to
|
|
find another solution.
|
|
|
|
What if rather than referencing a channel by its UTXO, we reference it based on
|
|
its "location" in the chain? In order to do this, we'll need a scheme that
|
|
allows us to "index" into a given block, then a transaction within that block,
|
|
and finally a specific output created by that transaction. Such an identifier
|
|
is described in BOLT 7 and is referred to as a: short channel ID, or `scid`.
|
|
The `scid` is used both in `channel_announcement` (and `channel_update`) as
|
|
well as within the onion encrypted routing packet included within HTLCs as we
|
|
learned in Chapter XX.
|
|
|
|
###### The Short Channel ID Identifier
|
|
|
|
Based on the information above, we have 3 piece of information we need to
|
|
encode in order to uniquely reference a given channel. As we want to very
|
|
compact representation, we'll attempt to encode the information into a _single_
|
|
integer using existing known bit packing techniques. Our integer format of
|
|
choice is an unsigned 64-bit integer, which is comprised of 8 logical bytes.
|
|
|
|
First, the block height. Using 3 bytes (24-bits) we can encode 16777216 blocks,
|
|
which is more than double the number of blocks that are attached to the current
|
|
mainnet Bitcoin blockchain. That leaves 5 bytes left for us to encode the
|
|
transaction index and the output index respectively. We'll then use the next 3
|
|
bytes to encode the transaction index _within_ a block. This is more than
|
|
enough given that it's only possible to fix tens of thousands of transactions
|
|
in a block at current block sizes. This leaves 2 bytes left for us to encode
|
|
the output index of the channel within the transaction.
|
|
|
|
Our final `scid` format resembles:
|
|
```
|
|
block_height (3 bytes) || transaction_index (3 bytes) || output_index (2 byes)
|
|
```
|
|
|
|
Using bit packing techniques, we first encode the most significant 3 bytes as
|
|
the block height, the next 3 bytes as the transaction index, and the least
|
|
significant 2 bytes as the output index of that creates the channel UTXO.
|
|
|
|
A short channel ID can be represented as a single integer
|
|
(`695313561322258433`) or as a more human friendly string: `632384x1568x1`.
|
|
Here we see the channel was mined in block `632384`, was the `1568` th
|
|
transaction in the block, with the channel output being found as the second
|
|
(UTXOs are zero-indexed) output produced by the transaction.
|
|
|
|
Now that we're able to succinctly defence a given channel in the chain, we can
|
|
now examine the full structure of the `channel_announcement` message, as well
|
|
as how to verify the proof-of-existence included within the message.
|
|
|
|
##### Channel Announcement Structure
|
|
|
|
A channel announcement primarily communicates two aspects:
|
|
|
|
1. A proof that a channel exists between Node A and Node B with both nodes
|
|
controlling the mulit-sig keys in the refracted channel output
|
|
|
|
2. The set of capabilities of the channel (what types of HTLCs can it route,
|
|
etc)
|
|
|
|
When describing the proof, we'll typically refer to node `1` and node `2`. Out
|
|
of the two nodes that a channel connects, the "first" node is the node that has
|
|
a "lower" public key encoding when we compare the public key of the two nodes
|
|
in compressed format hex-encoded in lexicographical order. Correspondingly, in
|
|
addition to a node public key on the network, each node should also control a
|
|
public key within the Bitcoin blockchain.
|
|
|
|
Similar to the `node_announcement` message, all included signatures of the
|
|
`channel_announcement` message should be signed/verified against the raw
|
|
encoding of the message (minus the header) that follows _after_ the final
|
|
signature (as it isn't possible for a signature to sign itself..)
|
|
|
|
With that said, a `channel_announcement` message (the edge descriptor in the
|
|
channel graph) has the following attributes:
|
|
|
|
* `node_signature_1`: The signature of the first node over the message digest.
|
|
|
|
* `node_signature_2`: The signature of the second node over the message
|
|
digest.
|
|
|
|
* `bitcoin_signature_1`: The signature of the multi-sig key (in the funding
|
|
output) of the first node over the message digest.
|
|
|
|
* `bitcoin_signature_2`: The signature of the multi-sig key (in the funding
|
|
output) of the second node over the message digest.
|
|
|
|
* `features`: A feature bitvector that describes the set of protocol level
|
|
features supported by this channel.
|
|
|
|
* `chain_hash`: A 32 byte hash which is typically the genesis block hash of
|
|
the chain the channel was opened within.
|
|
|
|
* `short_channel_id`: The `scid` that uniquely locates the given channel
|
|
within the blockchain.
|
|
|
|
* `node_id_1`: The public key of the first node in the network.
|
|
|
|
* `node_id_2`: The public key of the second node in the network.
|
|
|
|
* `bitcoin_key_1`: The raw multi-sig key for the channel funding output for
|
|
the first node in the network.
|
|
|
|
* `bitcoin_key_2`: The raw multi-sig key for the channel funding output for
|
|
the second node in the network.
|
|
|
|
##### Channel Announcement Validation
|
|
|
|
Now that we know what a `channel_announcement` contains. We can now move onto
|
|
to exactly _how_ to verify such an announcement.
|
|
|
|
|
|
#### Channel Update: Structure & Validation
|
|
|
|
|
|
// TODO(roasbeef): rename to "the structure of the channel graph"?
|
|
|
|
## Syncing the Channel Graph
|
|
|
|
|
|
|
|
* introduce the NodeAnnouncement (purpose structure validation)
|
|
* go thru fields, ref ability to use Tor, etc
|
|
* ref feature bits at high level, say will be covered in later chapter
|
|
* node announcement validation
|
|
* acceptance critera
|
|
|
|
|
|
### Channel Announcement
|
|
|
|
## Ongoing Channel Graph Maintenance
|
|
|
|
### Gossip Protocols in the Abstract
|
|
|
|
* what is a gossip protocol?
|
|
* why are they used?
|
|
* what other famous uses of gossip protocols are out there?
|
|
* when does it make sense to use a gossip protocol?
|
|
* what are some use a gossip protocol?
|
|
* why does LN uise
|
|
* questions to ask for gossip rptocol
|
|
* what is being gossiped
|
|
* what is the expected delay bound?
|
|
* how is DoS prevented
|
|
|
|
## Gossip in LN
|
|
|
|
### Channel Announcements
|
|
|
|
### Purpose
|
|
### Structure
|
|
### Validation
|
|
|
|
### Channel Updates
|
|
|
|
### Purpose
|
|
### Structure
|
|
### Validation
|
|
|
|
### Node Announcements
|
|
|
|
### Purpose
|
|
### Structure
|
|
### Validation
|
|
|
|
* anser the three quesitons above
|
|
|
|
* what: node info, chan info, channel updates
|
|
|
|
* delay: 2 week liveness assumption, otherwise pruned, keep alive updates
|
|
|
|
* DoS: real channel, proper validation of sigs, etc
|
|
|
|
# Conlusion
|