Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Sample architecture & code skeleton #2

Closed
wants to merge 96 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
2a7b6dd
Initial checkin
TheBlueMatt Jun 14, 2018
6d605a0
Set up events handling infra and stdin reading infra
TheBlueMatt Jun 16, 2018
3c8efd0
Add 3-msg outbound buffer
TheBlueMatt Jun 16, 2018
88bb166
Resolve fd duplication potential panic, just use ids
TheBlueMatt Jul 3, 2018
b4cd8b7
Switch to RPC from REST, cause duh
TheBlueMatt Jul 3, 2018
c91db72
Update for new rust-lightning API
TheBlueMatt Jul 3, 2018
3d49676
Implement block connection/disconnect notification
TheBlueMatt Jul 5, 2018
309dd0e
Move socket handling to another module
TheBlueMatt Jul 6, 2018
4718a0e
Support creating an outbound channel
TheBlueMatt Jul 6, 2018
841e300
Fix feerate rounding by adding 3 to per-weight feerate
TheBlueMatt Jul 6, 2018
f0a3324
Move chain monitoring into its own module
TheBlueMatt Jul 9, 2018
e23130a
Notify event processor when we have a block change
TheBlueMatt Jul 10, 2018
f6801f8
Fix initial chain monitor startup
TheBlueMatt Jul 19, 2018
8c9c4f9
Use &[] instead of &Vec for rpc_client calls
TheBlueMatt Jul 19, 2018
18af536
Implement event handling
TheBlueMatt Jul 19, 2018
2b23bc8
panic = abort
TheBlueMatt Jul 19, 2018
b877036
Implement channelmonitor storage
TheBlueMatt Jul 20, 2018
0c1872a
Clean up net_manager and update for new API
TheBlueMatt Jul 23, 2018
26f4554
Implement tx broadcast
TheBlueMatt Jul 23, 2018
1d56221
panic on mainnet (before we start adding *actual* commands
TheBlueMatt Jul 23, 2018
87e729b
Poke event handler on funding transaction generation
TheBlueMatt Jul 24, 2018
930fc09
Add some useful list/channel close commands
TheBlueMatt Jul 24, 2018
6dcb2b9
Set connect timeout to 10 secs
TheBlueMatt Jul 24, 2018
410cd60
Update for new fee API
TheBlueMatt Jul 25, 2018
6be34bb
Add sending via rust-lightning-invoice BOLT11 parsing
TheBlueMatt Jul 25, 2018
2722644
Fix error handling inbound reads due to wrong initialization
TheBlueMatt Jul 25, 2018
badc811
Handle PendingHTLCsForwardable events instead of panic()ing
TheBlueMatt Jul 25, 2018
b2b6685
Support receiving payments (no BOLT11 invoice creation yet)
TheBlueMatt Jul 25, 2018
a22fb7b
Only write one channel monitor update to disk at a time
TheBlueMatt Jul 25, 2018
27a15a9
Add basic README
TheBlueMatt Jul 25, 2018
fb49f55
Fix height off-by-one in block_connected event generation
TheBlueMatt Jul 31, 2018
4aecc8b
Fix RegTest/from-genesis-block-sync
TheBlueMatt Aug 1, 2018
8a54456
Update to latest rust-lightning{,-invoice} and secp256k1
TheBlueMatt Aug 21, 2018
33741ef
Update to crates rust-lightning! (and git invoice)
TheBlueMatt Sep 20, 2018
a3edeeb
Move some utility functions from main.rs to utils.rs
eupn Oct 9, 2018
e7e2eff
Update to rust-lightning 0.0.6
TheBlueMatt Oct 27, 2018
790ac27
Update to latest rust-lightning/bitcoin, gcc->cc
TheBlueMatt Nov 26, 2018
abacbb2
Import cooperative-close and ChannelMonitor-claim pubkeys on start
TheBlueMatt Nov 26, 2018
e3f144c
Fix invoice amount check
TheBlueMatt Nov 27, 2018
fb8d5f9
Update to git rust-lightning, released -invoice
TheBlueMatt Dec 22, 2018
d4cd1d4
Bump lightning-invoice, lightning, bitcoin, and bitcoin_hashes deps
TheBlueMatt Jan 25, 2019
5baa2f4
Move net handling into a new crate, use latest rust-bitcoin/lightn
TheBlueMatt Jun 1, 2019
4751bb6
Fix final_cltv parsing
TheBlueMatt Jun 1, 2019
6e68693
Generate invoices
TheBlueMatt Jun 1, 2019
81e4edf
panic = abort so tokio doesn't eat it
TheBlueMatt Jun 1, 2019
ba09882
Add force-close comamnd
TheBlueMatt Jun 1, 2019
827dd69
Fix missing-amount error/panic
TheBlueMatt Jun 1, 2019
1f5e84e
make port configurable
sgeisler Jun 1, 2019
ca8a35e
Add .gitignore
jtimon Jul 16, 2019
81fcff0
Introduce .travis.yml
jtimon Jul 27, 2019
70ddb47
Print error message for port parsing
TheBlueMatt Jun 1, 2019
1291093
Bump deps, make new rust warning-happy-ish
TheBlueMatt Dec 20, 2019
da3248c
Update to latest RL
TheBlueMatt Jan 27, 2020
720d01f
Cheat re: fee estimates on testnet
TheBlueMatt Jan 27, 2020
445808d
Print is_live value in l c and use more-stable "master + fixes" RL br…
TheBlueMatt Jan 28, 2020
fdd7d67
Partially implement claim, and update to latest RL claim structs
TheBlueMatt Jan 27, 2020
c7981ab
chore: add Cargo.lock to version control
squarfed Jan 23, 2020
f5afd16
Rewrite using async/await tokio 0.2.
TheBlueMatt Feb 1, 2020
e8c9e6a
Allow new Bitcoin Core versions with segwit buried
TheBlueMatt Feb 3, 2020
de43216
Make chain monitoring generic for replay + start with a given tip
TheBlueMatt Feb 14, 2020
e286075
Update to latest RL and rescan at startup!
TheBlueMatt Feb 15, 2020
6f2150f
print at better times during startup
TheBlueMatt Feb 15, 2020
d3d60df
Properly claim to a local address when claiming on chain funds
TheBlueMatt Feb 15, 2020
471d1fe
Load full hyper body instead of only chunks before processing
TheBlueMatt Feb 15, 2020
d088843
Call new timer functions every minute
TheBlueMatt Feb 15, 2020
a3e5d08
Print rust-lightning log entries to stderr
TheBlueMatt Feb 15, 2020
090391d
Allow loading monitors/managers which haven't seen blocks yet
TheBlueMatt Feb 15, 2020
caf9434
Confirm channels after only one block, instead of the default 6
TheBlueMatt Feb 15, 2020
509391d
Print txids after sendrawtransaction succeeds
TheBlueMatt Feb 15, 2020
df51703
Implement single-channel force-close
TheBlueMatt Feb 15, 2020
eded281
Bump dep head
TheBlueMatt Feb 15, 2020
1c42718
Fix getblockheader response parsing
TheBlueMatt Feb 17, 2020
0fa928a
Bump dep head and update to new API
TheBlueMatt Feb 21, 2020
7feb800
Add initial block height logic
TheBlueMatt Feb 21, 2020
48b25ed
We already call rebraodcast_txn() regularly, we don't need to poll
TheBlueMatt Feb 21, 2020
610ab74
set panic = abort
TheBlueMatt Feb 21, 2020
3feeebe
Correctly print the port number bound on at startup
TheBlueMatt Feb 23, 2020
537743a
Bump deps
TheBlueMatt Feb 23, 2020
c28a4c2
Serialize + load Router
TheBlueMatt Feb 24, 2020
0c9670d
Print RPC errors to stderr
TheBlueMatt Feb 24, 2020
053246d
Bump dep
TheBlueMatt Feb 24, 2020
aece171
Do io writes separately and dont hold locks during I/O
TheBlueMatt Feb 24, 2020
fddc088
Make amount explicit
TheBlueMatt Feb 24, 2020
58d7ee8
Add ability to broadcast our own node_announcement
TheBlueMatt Feb 24, 2020
2059704
bump deps
TheBlueMatt Feb 24, 2020
a4de1d5
Correct claim handling
TheBlueMatt Feb 25, 2020
679ee2b
bump dep head + use released tokio again
TheBlueMatt Feb 29, 2020
811d7c0
Print better error message if we fail to pass initial RPC check
TheBlueMatt Feb 29, 2020
b45f8c3
Include date but skip file path in log entries
TheBlueMatt Feb 29, 2020
d321872
Update RL
TheBlueMatt Feb 29, 2020
eb1faf0
Build regtest invoices
TheBlueMatt Mar 4, 2020
2143dd9
Bmp deps
TheBlueMatt Apr 30, 2020
855c77e
Switch to lightning-block-sync instead of our own block sync stuff
TheBlueMatt May 5, 2020
1f07441
Rewrite a multi-threaded daemon with distinct cli binary
Nov 5, 2020
6858cfa
Add a ARCH.md
Feb 9, 2021
6442370
TODO starter
ariard Feb 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk
*~
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
language: rust

rust:
- stable
- beta
- nightly

matrix:
allow_failures:
- rust: nightly
fast_finish: true

cache: cargo

script:
- cargo build --verbose --all
- cargo test --verbose --all
252 changes: 252 additions & 0 deletions ARCH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
The LDK sample is broken between 2 primary process : `ldk-node` and `ldk-cli`.

The `ldk-cli` is a simple JSON-RPC client to interact with the node.

The `ldk-node` is a multi-threaded process embedding all the main components of a regular Lightning
node :
* `MicroSPVClient`, a chain validation backend providing blocks updates, utxo filtering and utxo set access
* `ChainMonitor`, a chain processing entity enforcing onchain the channel logic negotiated offchain
* `EventHandler`, a default handler informing the client logic about internal events
* `ChannelManager`, a core lightning state machine, supervising channel lifecycle and payment initiation/relay
* `NetGraphMsgHandler`, a lightning router, handling gossips updates and providing payment path draws
* `PeerManager`, a lightning networking stack, managing peer connections lifecycle
* `setup_socket_listener`, a simple network handler to listen incoming connections
* `setup_rpc_server`, a simple RPC server handler to listen to `ldk-cli`

All those components are running in their own threads and interact through inter-threading
handlers powered by `tokio::sync::mpsc`.

# A Gentle Guided Tour of LDK-sample components

The initial step is to load state from previous node session and user config file. Note the sample
config file LdkConfig is wider than RL's UserConfig as it scopes daemon-specific configuration
variables (`bitcoind` RPC port, bitcoin network, ...)

```
let daemon_dir = if env::args().len() > 2 {
let path_dir = env::args().skip(2).next().unwrap();
let path = if fs::metadata(&path_dir).unwrap().is_dir() {
path_dir + "/ldk-node.conf"
} else { exit_on!("Need daemon directory to exist and be a directory"); };
path
} else {
let mut path = if let Some(path) = env::home_dir() {
path
} else { exit_on!("No home directory found"); };
path.push(".ldk-node/ldk-node.conf");
String::from_str(path.to_str().unwrap()).unwrap()
};

let ldk_config = LdkConfig::create(&daemon_dir);
```

The second step is establishing a connection with your Bitcoin validation backend. It should
always be recalled that your Lightning node must keep a lively view of the chain to ensure
security and well-accuracy of its operations. Note, you should also have permanent access to
the tx-relay p2p network and a trustworhty fee-estimation. For the sample, we opted to rely on
Bitcoin Core RPC interface, but other options such as Electrum or BIP157 can be envisioned.

```
let bitcoind_client = Arc::new(RpcClient::new(&ldk_config.get_str("bitcoind_credentials"), &ldk_config.get_str("bitcoind_hostport")));

let network = if let Ok(net) = ldk_config.get_network() {
net
} else { exit_on!("No network found in config file"); };

log_sample!(logger, "Checking validity of RPC URL to bitcoind...");
if let Ok(v) = bitcoind_client.make_rpc_call("getblockchaininfo", &[], false).await {
assert!(v["verificationprogress"].as_f64().unwrap() > 0.99);
assert!(
v["bip9_softforks"]["segwit"]["status"].as_str() == Some("active") ||
v["softforks"]["segwit"]["type"].as_str() == Some("buried"));
let bitcoind_net = match v["chain"].as_str().unwrap() {
"main" => constants::Network::Bitcoin,
"test" => constants::Network::Testnet,
"regtest" => constants::Network::Regtest,
_ => panic!("Unknown network type"),
};
if !(network == bitcoind_net) { exit_on!("Divergent network between LDK node and bitcoind"); }
} else { exit_on!("Failed to connect to bitcoind RPC server, check your `bitcoind_hostport`/`bitcoind_credentials` settings"); }

```

The third step is the initialization or loading of the LN-specific key material. Ideally this material
should be encrypted and replicated to increase security and fault-tolerance of your node. We're
using the default LDK key-management sample `KeysManager`).

```
let secp_ctx = Secp256k1::new();

let our_node_seed = if let Ok(seed) = fs::read(data_path.clone() + "/key_seed") {
assert_eq!(seed.len(), 32);
let mut key = [0; 32];
key.copy_from_slice(&seed);
key
} else {
let mut key = [0; 32];
thread_rng().fill_bytes(&mut key);
let mut f = fs::File::create(data_path.clone() + "/key_seed").unwrap();
f.write_all(&key).expect("Failed to write seed to disk");
f.sync_all().expect("Failed to sync seed to disk");
key
};
let cur = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
let keys = Arc::new(KeysManager::new(&our_node_seed, network, cur.as_secs(), cur.subsec_nanos()));
```

We previously established our connection through RPC with a Bitcoin Core. In the fourth step,
we'll use this RPC access to boostrap our chain backend client `MicroSPVClient`. This entity
is providing block connections/disconnections through the `ChainListener` interface
(implem `ChainConnector`, a subcomponent of `MicroSPVClient`).

Current consumers of those chain updates are `ChannelManager`/`ChainMonitor`/`NetworkGraphHandler`.
Requirements of these components will be detailed in further steps.

```
log_sample!(logger, "Starting chain backend thread...");

let (outbound_blocks_chan_manager, inbound_blocks_chan_manager) = mpsc::channel(100);

let buffer_blocks = Arc::new(ChainConnector::new());
let chain_listener = buffer_blocks.clone();

let (handle_1, handle_2) = setup_chain_backend(starting_blockhash.unwrap(), (ldk_config.get_str("bitcoind_credentials"), ldk_config.get_str("bitcoind_hostport")), buffer_blocks, chain_listener, outbound_blocks_chan_manager).await;
join_handles.push(handle_1);
join_handles.push(handle_2);
```

The fifth step is starting the chain processing thread. Onchain events to care about are numerous
and spread from revoked counterparty commitment to punish to monitoring channel outputs belonging to
us until they're reorg-safe to spend. The LDK sample is relying on the default RL implementation
`ChainMonitor`. This component relies on `MicroSPVClient` through the `chain::Filter` to register
UTXO to watch, `BroadcasterInterface` to propagate "reactive" transactions and `FeeEstimator` to
vet those transactions with a good feerate.

This component is critical for the safety of the Lightning node and its state should be dutifully
persisted and replicated. It will serves the `ChannelManager` as a `chain::Watch` interface.
TODO: code a connector linking ChainMonitor to ChannelManager.

```
log_sample!(logger, "Starting chain processing...");

let chain_source = Arc::new(ChainSource::new());
let handle = setup_chain_processing(chain_source.clone(), tx_broadcaster.clone(), fee_estimator.clone(), logger.clone(), persister.clone()).await;
join_handles.push(handle);
```

The sixth step is the warm up of an event handler thread. Current LDK sample handler is pretty
summary, and only covers notification of inbound connections. It might serve as a default endpoint
to propopagate `Events` to the client logic (e.g payment reception, peer disconnections, ...).

It receives updates from the peer manager thread through the `InboundEventConnector`.

```
log_sample!(logger, "Starting event handler...");

let (outbound_event_peers, inbound_event_peers) = mpsc::channel(1);
let (outbound_event_chan_manager, inbound_event_chan_manager) = mpsc::channel(1);

let inbound_event_connector = InboundEventConnector::new(inbound_event_peers, inbound_event_chan_manager);

let handle = setup_event_handler(inbound_event_connector).await;
join_handles.push(handle);
```

The seventh step is the most meaningful one of the initialization sequence, setting up `ChannelManager`.
This component is driving per-channels logics, receiving updates, dispatching them, relaying HTLCs,
initiating payments or receiving ones. It will consumes block updates from the connector `ChainConnector`,
produced by `MicroSPVClient`. For per-channel key material, it requires access to a `KeysInterface`
(implem `KeysManager`).

The LDK `ChannelManager thread is waiting RPC command on the `rpccmd` communication channel. Those
commands like `open` or `send` will trigger corresponding state updates in the channel targeted.
`MessageSendEvent` might be generated and send to the network thread through the `chanman_msg_events`/
`peerman_notify` communications channels.

Interactions with the network thread are bidirectional, which means that `ChannelManager` will also
consume network messages from the `netmsg` communication channel. Those messages are issued by a
connected peer and will also affect channel states.

It's also consuming network messages through the `netmsg` communication channel. Those messages are
issued by a connected peer and will also affect channel states and might trigger response back
to the network thread.

```
log_sample!(logger, "Starting channel manager...");

let (outbound_chanman_rpccmd, inbound_chanman_rpccmd) = mpsc::channel(1);
let (outbound_chanman_netmsg, inbound_chanman_netmsg) = mpsc::channel(1);
let (outbound_chanman_msg_events, inbound_chanman_msg_events) = mpsc::channel(1);
let (outbound_peerman_notify, inbound_peerman_notify) = mpsc::channel(1);

let outbound_chan_manager_connector = OutboundChanManagerConnector::new(outbound_chanman_msg_events, outbound_peerman_notify);

let chain_watchdog = Arc::new(ChainWatchdog::new());
let (handle_1, handle_2) = setup_channel_manager(inbound_chanman_rpccmd, inbound_chanman_netmsg, inbound_blocks_chan_manager, outbound_chan_manager_connector, network, fee_estimator.clone(), chain_watchdog.clone(), tx_broadcaster.clone(), logger.clone(), keys.clone(), config, 0, bitcoind_client.clone()).await;
join_handles.push(handle_1);
join_handles.push(handle_2);
```

To send payment, our `ChannelManager` requires access to the graph. LDK sample gossips handling
and routing processing is done by RL's default implementation `NetGraphMsgHandler`. This component
is dependent of `MicroSPVClient` to fetch and verify UTXO of announced channels. UTXO access
is provided through the `chain::Access` interface. TODO: actually do the communication channel for
this access.

```
log_sample!(logger, "Starting node router...");

let (outbound_router_rpccmd, inbound_router_rpccmd) = mpsc::channel(1);
let (outbound_router_rpcreply, inbound_router_rpcreply) = mpsc::channel(1);
let (outbound_routing_msg, inbound_routing_msg): (Sender<Event>, Receiver<Event>) = mpsc::channel(1);

let utxo_accessor = Arc::new(UtxoWatchdog::new());
let outbound_router_connector = OutboundRouterConnector::new(outbound_router_rpcreply);
let inbound_router_connector = InboundRouterConnector::new(inbound_router_rpccmd, inbound_router_rpcreply);
let handle = setup_router(outbound_router_connector, inbound_router_connector, utxo_accessor.clone(), logger.clone()).await;
join_handles.push(handle);
```

The ninth step is concerning the LN network stack, `PeerManager`. This thread handles network
encryption and messages traffic with Lightning peers. It's interacting with the RPC server through
the `peers_rpccmd` communication channel for network-related commands such as `connect`/`disconnect`.
It's also both in a role of producer/consumers w.rt to `ChannelManager`, relaying channel updates
messages (`update_add_htlc`, `commitment_signed`, ...) and consuming back `MessageSendEvent`. Note,
it will be also triggered by the inbound connection thread through the `new_inbound_connection`
callback.

```
log_sample!(logger, "Starting peer manager...");

let (outbound_peers_rpccmd, inbound_peers_rpccmd) = mpsc::channel(1);
let (outbound_socket_events, inbound_socket_events): (Sender<()>, Receiver<()>) = mpsc::channel(1);

let outbound_peer_manager_connector = Arc::new(OutboundPeerManagerConnector::new(outbound_event_peers)); //sender_routing_msg/sender_chan_msg
let buffer_netmsg = Arc::new(BufferNetMsg::new(inbound_chanman_msg_events));
let chan_handler = buffer_netmsg.clone();
```

The tenth step is setuping a small inbound connection thread, serving as an endpoint for any
Lightning network connections initiated by our peers. It's servicing on the configured LN port
from `LdkConfig` and will delay any furhter peer management processing to the corresponding `PeerManager`
thread.

```
log_sample!(logger, "Starting socket listener thread...");

let outbound_socket_listener_connector = OutboundSocketListenerConnector::new(outbound_socket_events); // outbound_socket_events
let handle = setup_socket_listener(peer_manager_arc, outbound_socket_listener_connector, ln_port).await;
join_handles.push(handle);
```
The last step to complete the initialization sequence is setting up a RPC server. Servicing the
`ldk-cli` binary, it will dispatch all available commands to the others components and route back
their results. Binding port is configurable through `LdkConfig`.

```
log_sample!(logger, "Starting rpc server thread...");

let outbound_rpc_server_connector = OutboundRPCServerConnector::new(outbound_peers_rpccmd, outbound_chanman_rpccmd, outbound_router_rpccmd);
let handles = setup_rpc_server(outbound_rpc_server_connector, ldk_port).await;
join_handles.push(handles);
```

44 changes: 44 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[package]
name = "ldk-sample"
version = "0.0.1"
authors = ["Matt Corallo <[email protected]>", "Antoine Riard <[email protected]>"]
build = "build.rs"
edition = "2018"

[dependencies]
bitcoin = "0.24"
bitcoin-bech32 = "0.7"
lightning = { git = "https://github.com/ariard/rust-lightning", rev = "c0d6b44" }
lightning-net-tokio = { git = "https://github.com/ariard/rust-lightning", rev = "c0d6b44" }
lightning-block-sync = { git = "https://github.com/ariard/rust-lightning", rev = "c0d6b44", features = ["rpc-client", "rest-client"] }
lightning-invoice = { git = "https://github.com/TheBlueMatt/rust-lightning-invoice", rev = "86f1dd0" }
lightning-persister = { git = "https://github.com/ariard/rust-lightning", rev = "c0d6b44" }
hyper = "0.13"
serde = "1"
serde_json = "1"
rand = "0.4"
futures-util = "0.3"
tokio = { version = "0.2", features = ["io-std", "io-util", "rt-threaded", "tcp", "time", "sync"] }
base64 = "0.9"
time = "0.2"

[profile.release]
panic = "abort"

[profile.dev]
panic = "abort"

[build-dependencies]
cc = "1.0"

[[bin]]
name = "ldk-node"
path = "src/init.rs"

[[bin]]
name = "ldk-cli"
path = "src/sample-cli.rs"

[lib]
name = "ldk"
path = "src/lib.rs"
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,17 @@
# ldk-sample
sample node implementation using LDK

Simple Sample rust-lightning-based Lightning Node

DO NOT USE IT ON MAINET, IT'LL BURN KITTENS AND LOSE YOUR MONEY !!!

Basic documentation is coming soon, but those commands should be working

```
./ldk-cli connect 03f2f14bfa554d0205847fbdf46f1948cdd5fa7911c2be95e50a7263e3d126fa95 127.0.0.1 9735

./ldk-cli open 03f2f14bfa554d0205847fbdf46f1948cdd5fa7911c2be95e50a7263e3d126fa95 12345 6789

./ldk-cli send 03f2f14bfa554d0205847fbdf46f1948cdd5fa7911c2be95e50a7263e3d126fa95 157230162837504 10
```


10 changes: 10 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extern crate cc;

fn main() {
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm")))]
{
let mut cfg = cc::Build::new();
cfg.file("src/rust_crypto_nonstd_arch.c");
cfg.compile("lib_rust_crypto_nonstd_arch.a");
}
}
14 changes: 14 additions & 0 deletions ldk-node.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Hostname:Port for JSON-RPC connections to bitcoind
bitcoind_hostport=127.0.0.1:18443

# Username:Password for JSON-RPC connections to bitcoind
bitcoind_credentials=bitcoinrpc:5f8a512a85ebb45be20bd36bfa0dc2f9

# Network
network=regtest

#Hostname:Port for JSON-RPC LDK RPC server
ln_hostport=127.0.0.1:9730

#Hostname:Port for LDK RPC server
ldk_hostport=127.0.0.1:7688
Loading