Skip to content

Commit afdcbf3

Browse files
Merge pull request #2 from valentinewallace/initial-skeleton
Initial website
2 parents 9f52f43 + d55fc06 commit afdcbf3

29 files changed

+11499
-2
lines changed

.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Dependencies
2+
/node_modules
3+
4+
# Production
5+
/build
6+
7+
# Generated files
8+
.docusaurus
9+
.cache-loader
10+
11+
# Misc
12+
.DS_Store
13+
.env.local
14+
.env.development.local
15+
.env.test.local
16+
.env.production.local
17+
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*

README.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1-
# lightningdevkit.org
2-
The dev website
1+
# Website
32

3+
This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator.
4+
5+
## Installation
6+
7+
```console
8+
yarn install
9+
```
10+
11+
## Local Development
12+
13+
```console
14+
yarn start
15+
```
16+
17+
This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server.
18+
19+
## Build
20+
21+
```console
22+
yarn build
23+
```
24+
25+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
26+
27+
## Deployment
28+
29+
```console
30+
GIT_USER=<Your GitHub username> USE_SSH=true yarn deploy
31+
```
32+
33+
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3+
};

docs/blockdata.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
id: blockdata
3+
title: Blockchain Data
4+
---
5+
6+
TODO

docs/build_node.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
---
2+
id: build_node
3+
title: "Building a Node: Checklist"
4+
---
5+
6+
## Introduction
7+
8+
This document is a few checklists for everything you need to make a node using LDK.
9+
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 most lightning operations you'll want to use, such as opening a channel
13+
14+
Note that LDK does not assume that safe shutdown is available, so there is no
15+
shutdown checklist.
16+
17+
This guide covers all major LDK operations besides sending and receiving payments,
18+
which are unsupported at the moment but Coming Soon^TM.
19+
20+
## Startup Checklist
21+
- [ ] Initialize the fee estimator
22+
* What it's used for: estimating fees for on-chain transactions that LDK wants broadcasted.
23+
* Dependencies: none
24+
25+
Example fee estimator that always returns `253` satoshis:
26+
```java
27+
// FeeEstimatorInterface is a functional interface, so we can implement it with a lambda
28+
final fee_estimator = FeeEstimator.new_impl((confirmation_target -> 253));
29+
```
30+
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.
31+
- [ ] Initialize the logger
32+
Example logger that prints to the console:
33+
```java
34+
// LoggerInterface is a functional interface, so we can implement it with a lambda
35+
final logger = Logger.new_impl((String arg) -> System.out.println(arg));
36+
```
37+
- [ ] Initialize the transaction broadcaster
38+
* What it's used for: broadcasting various lightning transactions
39+
* Dependencies: none
40+
* Example transaction broadcaster skeleton:
41+
```java
42+
// Note that the `tx` argument is a []byte type.
43+
final tx_broadcaster = BroadcasterInterface.new_impl(tx -> {
44+
<insert code to actually broadcast the given transaction here>
45+
});
46+
```
47+
- [ ] Initialize the channel data persister
48+
* What it's used for: persisting crucial channel data in a timely manner
49+
* Dependencies: none
50+
* Example:
51+
```java
52+
Persist persister = Persist.new_impl(new Persist.PersistInterface() {
53+
@Override
54+
public Result_NoneChannelMonitorUpdateErrZ persist_new_channel(OutPoint id, ChannelMonitor data) {
55+
byte[] channel_monitor_bytes = data.write();
56+
<insert code to write these bytes to disk, keyed by `OutPoint`>
57+
}
58+
59+
@Override
60+
public Result_NoneChannelMonitorUpdateErrZ update_persisted_channel(OutPoint id, ChannelMonitorUpdate update, ChannelMonitor data) {
61+
byte[] channel_monitor_bytes = data.write();
62+
<insert code to update the channel monitor's file on disk with these new bytes, keyed by `OutPoint`>
63+
}
64+
});
65+
```
66+
- [ ] Initialize the chain monitor
67+
* What it's used for: monitoring the chain for lighting transactions that are relevant to our node, and broadcasting force close transactions if need be
68+
* Dependencies: fee estimator, logger, transaction broadcaster, channel data persister
69+
* Optional dependency: a chain filter that allows LDK to let you know what transactions you should filter blocks for. This is useful if you pre-filter blocks or use compact filters. Otherwise, LDK will need full blocks.
70+
* Example:
71+
```java
72+
// Example of a ChainMonitor if you *are* running a light client or filtering for transactions:
73+
Filter tx_filter = Filter.new_impl(new Filter.FilterInterface() {
74+
@Override
75+
public void register_tx(byte[] txid, byte[] script_pubkey) {
76+
<insert code for you to watch for this transaction on-chain>
77+
}
78+
79+
@Override
80+
void register_output(OutPoint outpoint, byte[] script_pubkey) {
81+
<insert code for you to watch for this output on-chain>
82+
}
83+
});
84+
final chain_monitor = ChainMonitor.constructor_new(tx_filter, tx_broadcaster, logger, fee_estimator, persister);
85+
86+
// Example of a ChainMonitor if you are *not* running a light client and can provide
87+
full blocks:
88+
final chain_monitor = ChainMonitor.constructor_new(null, tx_broadcaster, logger, fee_estimator, persister);
89+
```
90+
- [ ] Initialize the keys manager
91+
* What it's used for: providing keys for signing lightning transactions
92+
* Dependencies: random bytes, the current bitcoin network
93+
* Example:
94+
```java
95+
byte[] key_seed = new byte[32];
96+
<insert code to fill key_seed with random bytes>
97+
// Notes about this KeysManager:
98+
// * it is parameterized by the mainnet bitcoin network, but this should be swapped out for testnet or regtest as needed.
99+
// * TODO document why the current time is part of the parameters
100+
KeysManager keys = KeysManager.constructor_new(key_seed, LDKNetwork.LDKNetwork_Bitcoin, System.currentTimeMillis() / 1000, (int) (System.currentTimeMillis() * 1000));
101+
```
102+
103+
See the Key Management guide for more information.
104+
- [ ] If LDK is restarting, fill in the chain monitor's existing channel monitor state
105+
* Dependencies: the keys manager
106+
* If LDK is restarting and has existing channels, then it's very important to read its current channel state off of disk during the restart process.
107+
* Equally important: when you read each channel monitor off of disk, it comes with a blockhash which was the last block the channel monitor saw. So it's very important to take this blockhash, and:
108+
1. If the blockhash is on a fork that's no longer current to the chain, then first you need to disconnect blocks until the channel monitor gets to the common ancestor with the main chain
109+
2. Then after this disconnection happens if it needs to, you then need to connect recent blocks until the channel monitor is at the current chain tip.
110+
111+
Example of reading channel monitors from disk, where each channel monitor's file is named after its funding outpoint:
112+
```java
113+
byte[] channel_monitor_bytes = <read the bytes from disk the same way you wrote them in step "Initialize the channel data persister">;
114+
Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ channel_monitor_read_result =
115+
UtilMethods.constructor_BlockHashChannelMonitorZ_read(monitor_bytes, keys_interface);
116+
117+
// Assert that the result of reading bytes from disk is OK.
118+
assert channel_monitor_read_result instanceof Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK;
119+
120+
// Cast the result of reading bytes from disk into its type in the `success` read case.
121+
TwoTuple<OutPoint, byte[]> funding_txo_and_monitor =
122+
((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ
123+
.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) channel_monitor_read_result)
124+
125+
// Cast the bytes in the result as a ChannelMonitor.
126+
ChannelMonitor monitor = ((Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ
127+
.Result_C2Tuple_BlockHashChannelMonitorZDecodeErrorZ_OK) res).res.b;
128+
129+
<insert code here to bring the channel monitor up to chain tip>
130+
131+
// Give the channel monitor to the chain monitor.
132+
final chain_watch = chain_monitor.as_Watch();
133+
chain_watch.watch_channel(mon.get_funding_txo().a, mon);
134+
```
135+
136+
Rust example of bringing a channel monitor up to chain tip: https://github.com/rust-bitcoin/rust-lightning/pull/763/files#diff-f457bab978fc8b89ad308d5195f99d7b65a4a6ba1673c5f164104b2dda9a0db6R251 where the channel monitor is the `chain_listener` parameter. See the linked function and the `find_fork` function within it.
137+
- [ ] Optional: initialize the router (which we call the `NetGraphMsgHandler`)
138+
* What it's used for: generating routes to send payments over
139+
* Dependencies: logger
140+
* Optional dependency: source of chain information, recommended for light clients to be able to verify channels
141+
* Example:
142+
```java
143+
final router = NetGraphMsgHandler.constructor_new(new byte[32], null, logger);
144+
```
145+
- [ ] Initialize the channel manager
146+
* What it's used for: managing channel state
147+
* Dependencies: keys manager, fee estimator, chain monitor, transaction broadcaster, logger, channel configuration info, and the set of channel monitors we read from disk in the previous step
148+
149+
Example of initializing a channel manager on a fresh node:
150+
```java
151+
final chain_watch = chain_monitor.as_Watch();
152+
// TODO: document the last param, that 1
153+
final channel_manager = ChannelManager.constructor_new(
154+
LDKNetwork.LDKNetwork_Bitcoin, FeeEstimator.new_impl(confirmation_target -> 0),
155+
chain_watch, tx_broadcaster, logger, keys_interface, UserConfig.constructor_default(), 1);
156+
```
157+
Example of initializing a channel manager on restart:
158+
```java
159+
byte[] serialized_channel_manager = <insert bytes you would have written in following the later step "Persist channel manager">;
160+
Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ channel_manager_read_result =
161+
UtilMethods.constructor_BlockHashChannelManagerZ_read(serialized_channel_manager,
162+
keys_interface, fee_estimator, chain_monitor.as_Watch(), tx_broadcaster, logger,
163+
UserConfig.constructor_default(), channel_monitors);
164+
165+
// Assert we were able to read successfully.
166+
assert channel_manager_read_result instanceof Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK;
167+
168+
final channel_manager = ((Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ
169+
.Result_C2Tuple_BlockHashChannelManagerZDecodeErrorZ_OK) channel_manager_read_result)
170+
.res.b;
171+
```
172+
- [ ] Initialize the peer manager using LDK's `PeerManager` struct combined with LDK's supplied `NioPeerHandler` networking battery
173+
* What it's used for: connecting to peers, facilitating peer data to and from LDK
174+
* Dependencies: channel manager, router (optional), keys manager, random bytes, logger
175+
* Example:
176+
```java
177+
byte[] random_data = new byte[32];
178+
<insert code to fill in `random_data` with random bytes>
179+
final nio_peer_handler;
180+
final peer_manager = PeerManager.constructor_new(chan_manager.as_ChannelMessageHandler(),
181+
router.as_RoutingMessageHandler(), keys_interface.get_node_secret(), random_data, logger);
182+
try { nio_peer_handler = new NioPeerHandler(peer_manager); } catch (IOException e) { assert false; }
183+
184+
// Finally, start NioPeerHandler listening for connections.
185+
final port = 9735;
186+
nio_peer_handler.bind_listener(new InetSocketAddress("127.0.0.1", port));
187+
```
188+
- [ ] Start a loop to handle the channel manager's generated events
189+
* What it's used for: the channel manager and chain monitor generate events that must be handled by you, such as telling you when a payment has been successfully received or when a funding transaction is ready for broadcast.
190+
* Dependencies: channel manager and chain monitor
191+
192+
Rust example: https://github.com/TheBlueMatt/rust-lightning-bitcoinrpc/blob/master/src/main.rs#L122
193+
- [ ] Persist channel manager: in the loop you started in the previous step, add the feature of persisting the channel manager after each event.
194+
* If the channel manager does not get persisted properly to disk, there is risk of channels force closing the next time LDK starts up. However, in this situation, no funds other than those used to pay force-closed channel fees are at risk of being lost.
195+
```java
196+
while (true) {
197+
<code from the previous step that handles channel manager events>
198+
...
199+
byte[] channel_manager_bytes_to_write = channel_manager.write();
200+
<insert code that writes these bytes to disk and/or backups>
201+
}
202+
```
203+
- [ ] Start a loop to call the channel manager's `timer_chan_freshness_every_min()` every minute
204+
* What it's used for: the channel manager needs to be told every time a minute passes so that it can broadcast fresh channel updates if needed
205+
Example:
206+
```java
207+
while (true) {
208+
<wait 60 seconds>
209+
channel_manager.timer_chan_freshness_every_min();
210+
}
211+
```
212+
213+
## Running LDK Checklist
214+
- [ ] Connect and disconnect blocks to LDK as they come in
215+
```java
216+
// header is a []byte type, height is `int`, txdata is a
217+
// TwoTuple<Long, byte[]>[], where the 0th element is block index and the 1st
218+
// element is the transaction bytes
219+
channel_manager.block_connected(header, txn, height);
220+
chain_monitor.block_connected(header, txn, height);
221+
222+
channel_manager.block_disconnected(header);
223+
chain_monitor.block_disconnected(header);
224+
```
225+
226+
## Using LDK
227+
- [ ] Opening a channel: see the "Opening a Channel" guide
228+
- [ ] Closing a channel
229+
* Dependencies: channel manager
230+
```java
231+
// Cooperative close:
232+
// Assuming 1 open channel
233+
byte[] channel_id = channel_manager.list_channels()[0].get_channel_id();
234+
Result_NoneAPIErrorZ close_result = channel_manager.close_channel(
235+
channel_id);
236+
assert close_result instanceof Result_NoneAPIErrorZ.Result_NoneAPIErrorZ_OK;
237+
// Make sure the peer manager processes this new event.
238+
nio_peer_handler.check_events();
239+
// LDK should give the transaction broadcaster a closing transaction to broadcast
240+
// after this
241+
242+
// Force close:
243+
// Assuming 1 open channel
244+
byte[] channel_id = channel_manager.list_channels()[0].get_channel_id();
245+
Result_NoneAPIErrorZ channel_manager.force_close_channel(channel_id);
246+
```
247+
- [ ] List open channels
248+
```java
249+
ChannelDetails[] channels = channel_manager.list_channels();
250+
```
251+
- [ ] Sending/receiving payments **NOTE: CURRENTLY UNSUPPORTED IN JAVA**
252+
* Currently unsatisfied dependencies:
253+
1. a way of constructing `NodeFeatures` and `ChannelFeatures` LDK structs (which should be exposed soon)
254+
2. a way to parse invoices (we need to generate bindings for the `rust-invoices` crate)
255+
- [ ] Connect to a peer
256+
* Dependencies: peer manager, peer's pubkey, peer's host and port
257+
258+
Example:
259+
```java
260+
byte[] peer_pubkey = <peer's pubkey bytes>
261+
int peer_port = 9745;
262+
SocketAddress peer_socket_addr = new InetSocketAddress("192.168.1.2", peer_port);
263+
nio_peer_handler.connect(peer_pubkey, peer_socket_address);
264+
```
265+
- [ ] List peers
266+
// TODO

docs/build_node2.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
id: build_node2
3+
title: Building a Node
4+
---
5+
6+
## Introduction
7+
In this guide, we'll be walking through how to build a lightning node using LDK in Java.
8+
9+
The process breaks down to 3 overarching steps:
10+
1. Initializing LDK's channel, peer, chain monitoring, and (optionally) routing objects on startup.
11+
* These objects will be parameterized by various other objects that can be from either your custom logic or one of LDK's supplied modules.
12+
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.
13+
3. Connect and disconnect blocks to LDK as they come in.
14+
15+
## Part 1: Startup
16+
// start w/ a diagram
17+
// could use a mac to do that
18+
19+
### Chain Monitoring
20+
At a high level, the first step is initializing a [`ChainMonitor` struct](https://docs.rs/lightning/0.0.12/lightning/chain/chainmonitor/struct.ChainMonitor.html) using [this]. See an example in one of our tests [in Java].
21+
22+
This will look something like this:
23+
```java
24+
logger = Logger.new_impl((String arg) -> System.out.println(seed + ": " + arg));
25+
fee_estimator = FeeEstimator.new_impl((confirmation_target -> 253));
26+
tx_broadcaster = BroadcasterInterface.new_impl(tx -> {
27+
// bro
28+
});
29+
```
30+
31+
<!-- At a high level, the first step is initiating the `ChainMonitor` struct. -->
32+
33+
<!-- For this step, you'll first need a few supporting objects that implements an interface. Each interface link is to the Rust docs which document the interface's requirements, and below is a sample of what the Java bindings should look like. -->
34+
<!-- 1. a logger, which is something that implements `LoggerInterface` -->
35+
<!-- ```java -->
36+
<!-- public static void main(String[] args) { -->
37+
<!-- // LoggerInterface is a functional interface, so we can implement it with a lambda -->
38+
<!-- final logger = Logger.new_impl((String log) -> System.out.println(log)); -->
39+
<!-- } -->
40+
<!-- ``` -->
41+
<!-- 2. a fee estimator, which is something that implements `FeeEstimatorInterface` -->
42+
<!-- ```java -->
43+
<!-- .. -->
44+
<!-- final fee_estimator = FeeEstimator.new_impl(( -->
45+
<!-- ``` -->
46+
<!-- 3. a transaction broadcaster, which is something that implements `TransactionBroadcasterInterface` -->
47+
48+
<!-- 4. a data persister, which is anything that implements `PersisterInterface` which is documented further [here], -->
49+
50+
<!-- We're now ready to initialize our chain monitor: -->
51+
<!-- ```java -->
52+
<!-- .. -->
53+
<!-- final chain_monitor = ChainMonitor.constructor_new(null, tx_broadcaster, logger, fee_estimator, persister); -->
54+
<!-- ``` -->
55+

0 commit comments

Comments
 (0)