|
1 | 1 | ---
|
2 | 2 | id: build_node
|
3 |
| -title: Building a Node |
| 3 | +title: "Building a Node: Checklist" |
4 | 4 | ---
|
5 | 5 |
|
6 | 6 | ## Introduction
|
7 |
| -In this guide, we'll be building a lightning node using LDK. |
8 | 7 |
|
9 |
| -The completed sample node built in this guide is available at [TODO(val) insert link]. *Not intended for use in production.* This node is built using the Java bindings. See [TODO(val)] for all LDK language bindings options. |
| 8 | +This document is a few checklists for everything you need to make a node using LDK. |
10 | 9 |
|
11 |
| -Whether your project is an existing bitcoin-only wallet or a lightning wallet, the core process for |
12 |
| -integrating LDK is the same. |
| 10 | +* The first checklist is everything you need to do on startup. |
| 11 | +* The second checklist is everything you need to do while LDK is running to keep it operational. |
| 12 | +* The third checklist covers lightning operations you'll want to use. |
13 | 13 |
|
14 |
| -The process breaks down to 3 overarching steps: |
15 |
| -1. Initializing LDK's channel, peer, chain monitoring, and (optionally) routing objects. |
16 |
| - * These objects will be parameterized by various other objects that can be from either your custom logic or one of LDK's supplied modules. |
17 |
| -<!-- 2. Starting loops to (a) poll for new peers and (b) tell LDK's channel and peer objects each time a minute passes, so they can properly maintain their state. --> |
18 |
| -2. Starting loops to (a) poll for new peers and (b) periodically nudge the channel and peer objects so they can properly maintain their state. |
19 |
| - * Specific instructions for existing lightning wallets is found in the Lightning Wallet Integration Guide. |
20 |
| -3. Connect and disconnect blocks to LDK as they come in. |
21 |
| - |
22 |
| -## Requirements |
23 |
| -0. Some basic lightning knowledge like e.g. what a channel is, what force-closing means. |
24 |
| -1. A regtest bitcoind node (see [TODO(val) link to polar] for an easy way to spin this up) |
25 |
| -2. Java (this was tested using Java 11) |
26 |
| -<!-- 3. LDK's Java bindings jar [TODO link] in your class path --> |
27 |
| -TODO revise requirements |
| 14 | +Note that LDK does not assume that safe shutdown is available, so there is no |
| 15 | +shutdown checklist. |
28 | 16 |
|
29 |
| -## Part 0: Setup |
30 |
| -Import the bindings to your Java file and define a `main()`: |
| 17 | +## Startup Checklist |
| 18 | +- [ ] Initialize the fee estimator |
| 19 | + * What it's used for: estimating fees for on-chain transactions that LDK wants broadcasted. |
| 20 | + * Dependencies: none |
| 21 | + * Example fee estimator that always returns `253` satoshis: |
| 22 | +```java |
| 23 | +// FeeEstimatorInterface is a functional interface, so we can implement it with a lambda |
| 24 | +final fee_estimator = FeeEstimator.new_impl((confirmation_target -> 253)); |
| 25 | +``` |
| 26 | + Rather than using static fees, you'll want to fill in the lambda with fetching up-to-date fees from a source like bitcoin core or your own API endpoint. |
| 27 | +- [ ] Initialize the logger |
| 28 | +- [ ] Initialize the transaction broadcaster |
| 29 | + * What it's used for: |
| 30 | + * Dependencies: none |
| 31 | + * Example transaction broadcaster skeleton: |
31 | 32 | ```java
|
32 |
| -import org.ldk.impl.bindings; |
| 33 | +final tx_broadcaster = BroadcasterInterface.new_impl(tx -> { |
| 34 | + // <insert code to actually broadcast the given transaction here> |
| 35 | +}); |
| 36 | +``` |
| 37 | +- [ ] Initialize the channel data persister |
| 38 | + * What it's used for: |
| 39 | + * Dependencies: none |
| 40 | + * Example: |
| 41 | +```java |
| 42 | +Persist persister = Persist.new_impl(new Persist.PersistInterface() { |
| 43 | + @Override |
| 44 | + public Result_NoneChannelMonitorUpdateErrZ persist_new_channel(OutPoint id, ChannelMonitor data) { |
| 45 | + TODO fill this in |
| 46 | + } |
33 | 47 |
|
34 |
| -public static void main(String[] args) { |
| 48 | + @Override |
| 49 | + public Result_NoneChannelMonitorUpdateErrZ update_persisted_channel(OutPoint id, ChannelMonitorUpdate update, ChannelMonitor data) { |
| 50 | + // TODO fill this in |
| 51 | + } |
| 52 | +}); |
| 53 | +``` |
| 54 | +- [ ] Initialize the chain monitor |
| 55 | + * What it's used for: |
| 56 | + * Dependencies: fee estimator, logger, transaction broadcaster, channel data persister |
| 57 | + * Optional dependency: ChainSource |
| 58 | + * Example: |
| 59 | +```java |
| 60 | +// The `null` here must be filled in with a struct if you are running a light client. |
| 61 | +final chain_monitor = ChainMonitor.constructor_new(null, tx_broadcaster, logger, fee_estimator, persister); |
| 62 | +``` |
| 63 | +- [ ] Fill in the chain monitor's channel monitor state if LDK is restarting |
| 64 | +// TODO: add reading existing monitors from disk and handling replaying blocks, handling forks |
| 65 | +- [ ] Initialize the keys manager |
| 66 | + * What it's used for: |
| 67 | + * Dependencies: random bytes, the current bitcoin network |
| 68 | + * Example: |
| 69 | +```java |
| 70 | +byte[] key_seed = new byte[32]; |
| 71 | +// <insert code to fill key_seed with random bytes> |
| 72 | +// Notes about this KeysManager: |
| 73 | +// * it is parameterized by the mainnet bitcoin network, but this should be swapped out for testnet or regtest as needed. |
| 74 | +// * TODO document why the current time is part of the parameters |
| 75 | +KeysManager keys = KeysManager.constructor_new(key_seed, LDKNetwork.LDKNetwork_Bitcoin, System.currentTimeMillis() / 1000, (int) (System.currentTimeMillis() * 1000)); |
| 76 | +``` |
| 77 | +- [ ] Initialize the router (which we call the `NetGraphMsgHandler`) |
| 78 | +// TODO add reading router data from disk if restarting |
| 79 | + * What it's used for: |
| 80 | + * Dependencies: logger |
| 81 | + * Optional dependency: source of chain information, recommended for light clients to be able to verify channels |
| 82 | + * Example: |
| 83 | +```java |
| 84 | +// TODO: have the example include reading from disk OR starting a new one |
| 85 | +final router = NetGraphMsgHandler.constructor_new(new byte[32], null, logger); |
| 86 | +``` |
| 87 | +- [ ] Initialize the channel manager |
| 88 | +// TODO add stuff if we're restarting/reading from disk |
| 89 | + * What it's used for: |
| 90 | + * Dependencies: |
| 91 | + * Optional dependency: |
| 92 | + * Example: |
| 93 | +```java |
| 94 | +``` |
| 95 | +- [ ] Initialize the peer manager using LDK's `PeerManager` struct combined with LDK's supplied `NioPeerHandler` networking module |
| 96 | + * What it's used for: |
| 97 | + * Dependencies: channel manager, router, keys manager, random bytes, logger |
| 98 | + * Example: |
| 99 | +```java |
| 100 | +byte[] random_data = new byte[32]; |
| 101 | +// <insert code to fill in `random_data` with random bytes> |
| 102 | +final nio_peer_handler; |
| 103 | +final peer_manager = PeerManager.constructor_new(chan_manager.as_ChannelMessageHandler(), router.as_RoutingMessageHandler(), keys_interface.get_node_secret(), random_data, logger); |
| 104 | +try { nio_peer_handler = new NioPeerHandler(peer_manager); } catch (IOException e) { assert false; } |
| 105 | +``` |
| 106 | +- [ ] Start a loop for the peer manager to accept new connections. |
| 107 | + * What it's used for: |
| 108 | + * Dependencies: |
| 109 | + * Optional dependency: |
| 110 | + * Example: |
| 111 | +```java |
| 112 | + TODO fix this example |
| 113 | + for (short i = 10_000; true; i++) { |
| 114 | + try { |
| 115 | + nio_peer_handler.bind_listener(new InetSocketAddress("127.0.0.1", i)); |
| 116 | + nio_port = i; |
| 117 | + break; |
| 118 | + } catch (IOException e) { assert i < 10_500; } |
| 119 | + } |
| 120 | +``` |
| 121 | +- [ ] Start a loop for processing the peer manager's events. |
| 122 | + * What it's used for: |
| 123 | + * Dependencies: |
| 124 | + * Example: |
| 125 | +```java |
| 126 | +``` |
| 127 | +- [ ] Connect to peers on startup |
| 128 | + * What it's used for: |
| 129 | + * Dependencies: |
| 130 | + * Example: |
| 131 | +```java |
| 132 | +``` |
| 133 | +- [ ] Start a loop to handle the channel manager's generated events |
| 134 | +// TODO add persisting the channel manager after handling each event |
| 135 | + * What it's used for: |
| 136 | + * Dependencies: |
| 137 | + * Example: |
| 138 | +```java |
| 139 | +``` |
| 140 | +- [ ] Persist router data in a background loop |
| 141 | +- [ ] Start a loop to call `timer_chan_freshness_every_min` every minute |
35 | 142 |
|
36 |
| -} |
| 143 | +## Running LDK Checklist |
| 144 | +- [ ] Connect and disconnect blocks to LDK as they come in |
| 145 | +```java |
| 146 | +channel_manager.block_connected(header, txn, height); |
| 147 | +chain_monitor.block_connected(header, txn, height); |
37 | 148 | ```
|
38 | 149 |
|
39 |
| -## Part 1: Managing Channels |
40 |
| -We'll start by initializing probably the most core struct to Rust-Lightning (see FAQs[TODO add link] for the difference between Rust-Lightning and LDK): the channel manager. |
| 150 | +## Using LDK |
| 151 | +- [ ] opening/closing channels |
| 152 | +- [ ] sending payments and getting the result of the payment |
| 153 | +- [ ] connecting/disconnecting peers |
41 | 154 |
|
42 |
| -First, we'll initialize the objects that the channel manager is parameterized by. |
43 |
| -// fee estimator, chain_watch, tx broadcaster, logger, keys interface, |
44 | 155 |
|
45 |
| -## Part 1: Chain Monitoring |
46 |
| -Every lightning implementation needs a way to watch for relevant transactions appearing on-chain. |
| 156 | +<!-- In this guide, we'll be building a lightning node using LDK. --> |
47 | 157 |
|
48 |
| -### Setup |
49 |
| -But first, some housekeeping. |
| 158 | +<!-- The completed sample node built in this guide is available at [TODO(val) insert link]. *Not intended for use in production.* This node is built using the Java bindings. See [TODO(val)] for all LDK language bindings options. --> |
50 | 159 |
|
51 |
| -1. Within `main`, initialize a logger. A logger can be anything that satisfies the `LoggerInterface` interface [TODO add link]. In this case, we'll just print to the console. |
| 160 | +<!-- Whether your project is an existing bitcoin-only wallet or a lightning wallet, the core process for --> |
| 161 | +<!-- integrating LDK is the same. --> |
52 | 162 |
|
53 |
| -```java |
54 |
| -public static void main(String[] args) { |
55 |
| - // LoggerInterface is a functional interface, so we can implement it with a lambda |
56 |
| - final logger = Logger.new_impl((String log) -> System.out.println(log)); |
57 |
| -} |
58 |
| -``` |
| 163 | +<!-- The process breaks down to 3 overarching steps: --> |
| 164 | +<!-- 1. Initializing LDK's channel, peer, chain monitoring, and (optionally) routing objects. --> |
| 165 | +<!-- * These objects will be parameterized by various other objects that can be from either your custom logic or one of LDK's supplied modules. --> |
| 166 | +<!-- 2. Starting loops to (a) poll for new peers and (b) tell LDK's channel and peer objects each time a minute passes, so they can properly maintain their state. --> |
| 167 | +<!-- 2. Starting loops to (a) poll for new peers and (b) periodically nudge the channel and peer objects so they can properly maintain their state. --> |
| 168 | +<!-- 3. Connect and disconnect blocks to LDK as they come in. --> |
59 | 169 |
|
60 |
| -2. Add an on-chain fee estimator, which is anything that satisfies the `FeeEstimatorInterface` interface [TODO add link]. We need this because LDK's chain monitoring logic is responsible for broadcasting force-close transactions. |
| 170 | +<!-- ## Requirements --> |
| 171 | +<!-- 0. Some basic lightning knowledge like e.g. what a channel is, what force-closing means. --> |
| 172 | +<!-- 1. A regtest bitcoind node (see [TODO(val) link to polar] for an easy way to spin this up) --> |
| 173 | +<!-- 2. Java (this was tested using Java 11) --> |
| 174 | +<!-- 3. LDK's Java bindings jar [TODO link] in your class path --> |
| 175 | +<!-- TODO revise requirements --> |
61 | 176 |
|
62 |
| -```java |
63 |
| - .. |
64 |
| - final fee_estimator = FeeEstimator.new_impl(( |
65 |
| -``` |
| 177 | +<!-- ## Part 0: Setup --> |
| 178 | +<!-- Import the bindings to your Java file and define a `main()`: --> |
| 179 | +<!-- ```java --> |
| 180 | +<!-- import org.ldk.impl.bindings; --> |
66 | 181 |
|
67 |
| -3. Add a transaction broadcaster, which is anything that satisfies the `TransactionBroadcasterInterface` interface. We need this to broadcast the force-closing transaction if need be. |
68 |
| -```java |
69 |
| - .. |
70 |
| - final tx_broadcaster = |
71 |
| -``` |
| 182 | +<!-- public static void main(String[] args) { --> |
72 | 183 |
|
| 184 | +<!-- } --> |
| 185 | +<!-- ``` --> |
73 | 186 |
|
74 |
| -4. Add a data persister, which is anything that satisfies the `PersisterInterface` interface. We need this because our chain monitoring system also needs to ensure that crucial channel data is pesisted to disk and/or backups. |
75 |
| -```java |
76 |
| - .. |
77 |
| - final persister = |
78 |
| -``` |
| 187 | +<!-- ## Part 1: Managing Channels --> |
| 188 | +<!-- We'll start by initializing probably the most core struct to Rust-Lightning (see FAQs[TODO add link] for the difference between Rust-Lightning and LDK): the channel manager. --> |
79 | 189 |
|
80 |
| -We're now ready to initialize our chain monitor. |
| 190 | +<!-- First, we'll initialize the objects that the channel manager is parameterized by. --> |
| 191 | +<!-- // fee estimator, chain_watch, tx broadcaster, logger, keys interface, --> |
81 | 192 |
|
82 |
| -```java |
83 |
| - .. |
84 |
| - final chain_monitor = ChainMonitor.constructor_new(null, tx_broadcaster, logger, fee_estimator, persister); |
85 |
| -``` |
| 193 | +<!-- ## Part 1: Set up Objects Used For Chain Monitoring --> |
| 194 | +<!-- Every lightning implementation needs a way to watch for relevant transactions appearing on-chain. --> |
| 195 | + |
| 196 | +<!-- ### Setup --> |
| 197 | +<!-- But first, some housekeeping. --> |
| 198 | + |
| 199 | +<!-- 1. Within `main`, initialize a logger. A logger can be anything that satisfies the `LoggerInterface` interface [TODO add link]. In this case, we'll just print to the console. --> |
| 200 | +
|
| 201 | +<!-- ```java --> |
| 202 | +<!-- public static void main(String[] args) { --> |
| 203 | +<!-- // LoggerInterface is a functional interface, so we can implement it with a lambda --> |
| 204 | +<!-- final logger = Logger.new_impl((String log) -> System.out.println(log)); --> |
| 205 | +<!-- } --> |
| 206 | +<!-- ``` --> |
| 207 | +
|
| 208 | +<!-- 2. Add an on-chain fee estimator, which is anything that satisfies the `FeeEstimatorInterface` interface [TODO add link]. We need this because LDK's chain monitoring logic is responsible for broadcasting force-close transactions. --> |
| 209 | + |
| 210 | +<!-- ```java --> |
| 211 | +<!-- .. --> |
| 212 | +<!-- final fee_estimator = FeeEstimator.new_impl(( --> |
| 213 | +<!-- ``` --> |
| 214 | + |
| 215 | +<!-- 3. Add a transaction broadcaster, which is anything that satisfies the `TransactionBroadcasterInterface` interface. We need this to broadcast the force-closing transaction if need be. --> |
| 216 | +<!-- ```java --> |
| 217 | +<!-- .. --> |
| 218 | +<!-- final tx_broadcaster = --> |
| 219 | +<!-- ``` --> |
| 220 | + |
| 221 | + |
| 222 | +<!-- 4. Add a data persister, which is anything that satisfies the `PersisterInterface` interface. We need this because our chain monitoring system also needs to ensure that crucial channel data is pesisted to disk and/or backups. --> |
| 223 | +<!-- ```java --> |
| 224 | +<!-- .. --> |
| 225 | +<!-- final persister = --> |
| 226 | +<!-- ``` --> |
| 227 | + |
| 228 | +<!-- We're now ready to initialize our chain monitor. --> |
| 229 | +
|
| 230 | +<!-- ```java --> |
| 231 | +<!-- .. --> |
| 232 | +<!-- final chain_monitor = ChainMonitor.constructor_new(null, tx_broadcaster, logger, fee_estimator, persister); --> |
| 233 | +<!-- ``` --> |
| 234 | +
|
| 235 | +<!-- Next, we'll add the feature of telling this object whenever we receive a connected or disconnected block. --> |
| 236 | + |
| 237 | + |
| 238 | +<!-- ## --> |
| 239 | + |
| 240 | +<!-- // do it in the checklist format` --> |
| 241 | + |
| 242 | +<!-- [ ] fee estimator --> |
| 243 | +<!-- < code sample> --> |
| 244 | + |
| 245 | +<!-- [ ] tx broadcaster and a brief "what it's used for/context/info for each one --> |
| 246 | +<!-- <Desription> --> |
| 247 | +<!-- What it's used for: ... --> |
| 248 | +<!-- What it depends on: ... --> |
| 249 | +
|
| 250 | +<!-- < code sample w/ comments AND commentary> --> |
86 | 251 |
|
87 |
| -Next, we'll add the feature of telling this object whenever we receive a connected or disconnected block. |
| 252 | +<!-- [ ] this depend son these items --> |
| 253 | +<!-- ... --> |
| 254 | +<!-- [ ] start loop to receive new peers --> |
| 255 | +<!-- [ ] start loop to persist (these can be combined.. with these) --> |
| 256 | +<!-- [ ] --> |
88 | 257 |
|
89 | 258 |
|
90 |
| -## |
| 259 | +<!-- get a meeting w/ matt --> |
| 260 | +<!-- - write the checklist and then check w/ him --> |
| 261 | +<!-- just the checklist itself --> |
0 commit comments