]> git.bitcoin.ninja Git - ldk-sample/commitdiff
Add readme, fix license and a few other cleanups
authorValentine Wallace <vwallace@protonmail.com>
Thu, 18 Mar 2021 16:00:01 +0000 (12:00 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Mon, 3 May 2021 22:29:52 +0000 (18:29 -0400)
Cargo.lock
Cargo.toml
README.md
src/bitcoind_client.rs
src/cli.rs
src/disk.rs
src/main.rs

index 6204cdd9880122ad2657aaa4569bb6c6fb60bff2..aa92a5ec4142dd4e17f6694c1acfba4acd1a5c14 100644 (file)
@@ -6,15 +6,6 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
-[[package]]
-name = "background-processor"
-version = "0.1.0"
-dependencies = [
- "bitcoin",
- "lightning",
- "lightning-persister",
-]
-
 [[package]]
 name = "base-x"
 version = "0.2.8"
@@ -239,13 +230,13 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 name = "ldk-tutorial-node"
 version = "0.1.0"
 dependencies = [
- "background-processor",
  "base64",
  "bech32 0.7.2",
  "bitcoin",
  "bitcoin-bech32",
  "hex",
  "lightning",
+ "lightning-background-processor",
  "lightning-block-sync",
  "lightning-invoice",
  "lightning-net-tokio",
@@ -264,14 +255,26 @@ checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
 
 [[package]]
 name = "lightning"
-version = "0.0.12"
+version = "0.0.13"
+source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
 dependencies = [
  "bitcoin",
 ]
 
+[[package]]
+name = "lightning-background-processor"
+version = "0.0.13"
+source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
+dependencies = [
+ "bitcoin",
+ "lightning",
+ "lightning-persister",
+]
+
 [[package]]
 name = "lightning-block-sync"
-version = "0.0.1"
+version = "0.0.13"
+source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
 dependencies = [
  "bitcoin",
  "chunked_transfer",
@@ -284,6 +287,7 @@ dependencies = [
 [[package]]
 name = "lightning-invoice"
 version = "0.4.0"
+source = "git+https://github.com/rust-bitcoin/rust-lightning-invoice?rev=aa3a57b9dca5205fa25fa333a2db165d7e77b3b0#aa3a57b9dca5205fa25fa333a2db165d7e77b3b0"
 dependencies = [
  "bech32 0.7.2",
  "bitcoin_hashes",
@@ -293,7 +297,8 @@ dependencies = [
 
 [[package]]
 name = "lightning-net-tokio"
-version = "0.0.5"
+version = "0.0.13"
+source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
 dependencies = [
  "bitcoin",
  "lightning",
@@ -302,7 +307,8 @@ dependencies = [
 
 [[package]]
 name = "lightning-persister"
-version = "0.0.1"
+version = "0.0.13"
+source = "git+https://github.com/rust-bitcoin/rust-lightning?rev=32f6205848806a3b2876a2ae36b1db7d5fa22f7d#32f6205848806a3b2876a2ae36b1db7d5fa22f7d"
 dependencies = [
  "bitcoin",
  "libc",
index 7c097ca0850847e0109b8723944eb975f93ef2fc..1dd17c0165a9cfba80672ceec620729a20ff5346 100644 (file)
@@ -2,31 +2,24 @@
 name = "ldk-tutorial-node"
 version = "0.1.0"
 authors = ["Valentine Wallace <vwallace@protonmail.com>"]
+license = "MIT OR Apache-2.0"
 edition = "2018"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-# background-processor = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "d6f41d3c0b38b9ec9e06a3acfdd9f4b1d007a27d" }
-background-processor = { path = "../rust-lightning/background-processor" } 
+lightning-background-processor = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
 base64 = "0.13.0"
 bitcoin = "0.26"
 bitcoin-bech32 = "0.7"
 bech32 = "0.7"
 hex = "0.3"
-# lightning = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "c35002fa9c16042badfa5e7bf819df5f1d2ae60a" }
-lightning = { path = "../rust-lightning/lightning" }
-lightning-block-sync = { path = "../rust-lightning/lightning-block-sync", features = ["rpc-client"] }
-# lightning-invoice = { git = "https://github.com/rust-bitcoin/rust-lightning-invoice", rev = "ea25dc7e46a6339493032c500db4fe3a8fdb1acd" }
-lightning-invoice = { path = "../rust-lightning-invoice" }
-# lightning-net-tokio = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "ff00f6f8861419b73269e6c51d75ac9de75f1d1f" }
-lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
-# lightning-persister = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "aa127f55edc4439b03426644d178e402397329e8" }
-lightning-persister = { path = "../rust-lightning/lightning-persister" }
+lightning = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-block-sync = { git = "https://github.com/rust-bitcoin/rust-lightning", features = ["rpc-client"], rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-invoice = { git = "https://github.com/rust-bitcoin/rust-lightning-invoice", rev = "aa3a57b9dca5205fa25fa333a2db165d7e77b3b0" }
+lightning-net-tokio = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
+lightning-persister = { git = "https://github.com/rust-bitcoin/rust-lightning", rev = "32f6205848806a3b2876a2ae36b1db7d5fa22f7d" }
 time = "0.2"
 rand = "0.4"
 serde_json = { version = "1.0" }
-# tokio = { version = "0.2", features = ["io-std", "io-util", "rt-threaded", "tcp", "time", "sync"] }
-# tokio = { version = "1.0", features = [ "full", "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }
-# tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }
 tokio = { version = "1.0", features = [ "io-util", "macros", "rt", "rt-multi-thread", "sync", "net", "time" ] }
index 6358f4ff81e5cac1ce012d546bd7637983cbd8ab..740aa25b735defcb3afe66819edb74fb33025fca 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,5 +1,19 @@
 # ldk-sample
-sample node implementation using LDK
+Sample node implementation using LDK.
+
+## Installation
+```
+git clone git@github.com:valentinewallace/ldk-sample.git
+```
+
+## Usage
+```
+cd ldk-sample
+cargo run <bitcoind-rpc-username>:<bitcoind-rpc-password>@<bitcoind-rpc-host>:<bitcoind-rpc-port> <ldk_storage_directory_path> [<ldk-peer-listening-port>] [bitcoin-network]
+```
+`bitcoin-network`: defaults to `testnet`. Options: `testnet`, `regtest`.
+
+`ldk-peer-listening-port`: defaults to 9735.
 
 ## License
 
index de9f870f67061210d0e212f5ae801815d3c017b7..71e6272fbce7969ad6f3583738333b4356659c39 100644 (file)
@@ -36,7 +36,6 @@ impl BitcoindClient {
             rpc_user,
             rpc_password,
             runtime: Mutex::new(Runtime::new().unwrap()),
-            // runtime: Mutex::new(runtime),
         };
         Ok(client)
     }
@@ -103,7 +102,8 @@ impl FeeEstimator for BitcoindClient {
             ConfirmationTarget::HighPriority => (6, "ECONOMICAL", 50000),
         };
 
-        // If we're already in a tokio runtime, then we need to get out of it before we can broadcast.
+        // This function may be called from a tokio runtime, or not. So we need to check before
+        // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
         let conf_target_json = serde_json::json!(conf_target);
         let estimate_mode_json = serde_json::json!(estimate_mode);
         let resp = match Handle::try_current() {
@@ -131,7 +131,8 @@ impl BroadcasterInterface for BitcoindClient {
         let runtime = self.runtime.lock().unwrap();
 
         let tx_serialized = serde_json::json!(encode::serialize_hex(tx));
-        // If we're already in a tokio runtime, then we need to get out of it before we can broadcast.
+        // This function may be called from a tokio runtime, or not. So we need to check before
+        // making the call to avoid the error "cannot run a tokio runtime from within a tokio runtime".
         match Handle::try_current() {
             Ok(_) => {
                 tokio::task::block_in_place(|| {
index 20c43147a6369634f83c0c00a22d181eb6561c35..1e11086b6ab078ba0d781fa2f369b2235fbcce76 100644 (file)
@@ -3,8 +3,8 @@ use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256Hash;
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::secp256k1::key::{PublicKey, SecretKey};
-use crate::{ChannelManager, FilesystemLogger, HTLCDirection, HTLCStatus, NETWORK,
-            PaymentInfoStorage, PeerManager};
+use crate::{ChannelManager, FilesystemLogger, HTLCDirection, HTLCStatus,
+            PaymentInfoStorage, PeerManager, SatoshiAmount};
 use crate::disk;
 use crate::hex_utils;
 use lightning::chain;
@@ -34,11 +34,12 @@ pub(crate) struct LdkUserInfo {
     pub(crate) bitcoind_rpc_host: String,
     pub(crate) ldk_storage_dir_path: String,
     pub(crate) ldk_peer_listening_port: u16,
+    pub(crate) network: Network,
 }
 
 pub(crate) fn parse_startup_args() -> Result<LdkUserInfo, ()> {
     if env::args().len() < 4 {
-        println!("ldk-tutorial-node requires 3 arguments: `cargo run <bitcoind-rpc-username>:<bitcoind-rpc-password>@<bitcoind-rpc-host>:<bitcoind-rpc-port> ldk_storage_directory_path [optional: <ldk-incoming-peer-listening-port>]`");
+        println!("ldk-tutorial-node requires 3 arguments: `cargo run <bitcoind-rpc-username>:<bitcoind-rpc-password>@<bitcoind-rpc-host>:<bitcoind-rpc-port> ldk_storage_directory_path [<ldk-incoming-peer-listening-port>] [bitcoin-network]`");
         return Err(())
     }
     let bitcoind_rpc_info = env::args().skip(1).next().unwrap();
@@ -64,10 +65,25 @@ pub(crate) fn parse_startup_args() -> Result<LdkUserInfo, ()> {
 
     let ldk_storage_dir_path = env::args().skip(2).next().unwrap();
 
+    let mut ldk_peer_port_set = true;
     let ldk_peer_listening_port: u16 = match env::args().skip(3).next().map(|p| p.parse()) {
         Some(Ok(p)) => p,
         Some(Err(e)) => panic!(e),
-        None => 9735,
+        None => {
+            ldk_peer_port_set = false;
+            9735
+        },
+    };
+
+    let arg_idx = match ldk_peer_port_set {
+        true => 4,
+        false => 3,
+    };
+    let network: Network = match env::args().skip(arg_idx).next().as_ref().map(String::as_str) {
+        Some("testnet") => Network::Testnet,
+        Some("regtest") => Network::Regtest,
+        Some(_) => panic!("Unsupported network provided. Options are: `regtest`, `testnet`"),
+        None => Network::Testnet
     };
     Ok(LdkUserInfo {
         bitcoind_rpc_username,
@@ -76,6 +92,7 @@ pub(crate) fn parse_startup_args() -> Result<LdkUserInfo, ()> {
         bitcoind_rpc_port,
         ldk_storage_dir_path,
         ldk_peer_listening_port,
+        network,
     })
 }
 
@@ -84,8 +101,8 @@ pub(crate) fn poll_for_user_input(peer_manager: Arc<PeerManager>, channel_manage
                                   chain::Access>, Arc<FilesystemLogger>>>, payment_storage:
                                   PaymentInfoStorage, node_privkey: SecretKey, event_notifier:
                                   mpsc::Sender<()>, ldk_data_dir: String, logger: Arc<FilesystemLogger>,
-                                  runtime_handle: Handle) {
-    println!("LDK startup successful. To view available commands: \"help\".\nLDK logs are available in the `logs` folder of <your-supplied-ldk-data-dir-path>/.ldk/logs");
+                                  runtime_handle: Handle, network: Network) {
+    println!("LDK startup successful. To view available commands: \"help\".\nLDK logs are available at <your-supplied-ldk-data-dir-path>/.ldk/logs");
     let stdin = io::stdin();
     print!("> "); io::stdout().flush().unwrap(); // Without flushing, the `>` doesn't print
     for line in stdin.lock().lines() {
@@ -165,28 +182,30 @@ pub(crate) fn poll_for_user_input(peer_manager: Arc<PeerManager>, channel_manage
                         None => None
                     };
 
+                    // rust-lightning-invoice doesn't currently support features, so we parse features
+                    // manually from the invoice.
                     let mut invoice_features = InvoiceFeatures::empty();
                     for field in &invoice.into_signed_raw().raw_invoice().data.tagged_fields {
                         match field {
                             lightning_invoice::RawTaggedField::UnknownSemantics(vec) => {
                                 if vec[0] == bech32::u5::try_from_u8(5).unwrap() {
                                     if vec.len() >= 6 && vec[5].to_u8() & 0b10000 != 0 {
-                                        invoice_features.set_supports_var_onion_optin();
+                                        invoice_features = invoice_features.set_variable_length_onion_optional();
                                     }
                                     if vec.len() >= 6 && vec[5].to_u8() & 0b01000 != 0 {
-                                        invoice_features.set_requires_var_onion_optin();
+                                        invoice_features = invoice_features.set_variable_length_onion_required();
                                     }
                                     if vec.len() >= 4 && vec[3].to_u8() & 0b00001 != 0 {
-                                        invoice_features.set_supports_payment_secret();
+                                        invoice_features = invoice_features.set_payment_secret_optional();
                                     }
                                     if vec.len() >= 5 && vec[4].to_u8() & 0b10000 != 0 {
-                                        invoice_features.set_requires_payment_secret();
+                                        invoice_features = invoice_features.set_payment_secret_required();
                                     }
                                     if vec.len() >= 4 && vec[3].to_u8() & 0b00100 != 0 {
-                                        invoice_features.set_supports_basic_mpp();
+                                        invoice_features = invoice_features.set_basic_mpp_optional();
                                     }
                                     if vec.len() >= 4 && vec[3].to_u8() & 0b00010 != 0 {
-                                        invoice_features.set_requires_basic_mpp();
+                                        invoice_features = invoice_features.set_basic_mpp_required();
                                     }
                                 }
                             },
@@ -215,7 +234,7 @@ pub(crate) fn poll_for_user_input(peer_manager: Arc<PeerManager>, channel_manage
                         print!("> "); io::stdout().flush().unwrap(); continue;
                     }
                     get_invoice(amt_sat.unwrap(), payment_storage.clone(), node_privkey.clone(),
-                                       channel_manager.clone(), router.clone());
+                                channel_manager.clone(), network);
                 },
                 "connectpeer" => {
                     let peer_pubkey_and_ip_addr = words.next();
@@ -277,7 +296,7 @@ pub(crate) fn poll_for_user_input(peer_manager: Arc<PeerManager>, channel_manage
 }
 
 fn help() {
-    println!("openchannel pubkey@host:port channel_amt_satoshis");
+    println!("openchannel pubkey@host:port <channel_amt_satoshis>");
     println!("sendpayment <invoice>");
     println!("getinvoice <amt_in_satoshis>");
     println!("connectpeer pubkey@host:port");
@@ -313,10 +332,15 @@ fn list_payments(payment_storage: PaymentInfoStorage) {
     let payments = payment_storage.lock().unwrap();
     print!("[");
     for (payment_hash, payment_info) in payments.deref() {
+        let direction_str = match payment_info.1 {
+            HTLCDirection::Inbound => "inbound",
+            HTLCDirection::Outbound => "outbound",
+        };
         println!("");
         println!("\t{{");
+        println!("\t\tamount_satoshis: {},", payment_info.3);
         println!("\t\tpayment_hash: {},", hex_utils::hex_str(&payment_hash.0));
-        println!("\t\thtlc_direction: {},", if payment_info.1 == HTLCDirection::Inbound { "inbound" } else { "outbound" });
+        println!("\t\thtlc_direction: {},", direction_str);
         println!("\t\thtlc_status: {},", match payment_info.2 {
             HTLCStatus::Pending => "pending",
             HTLCStatus::Succeeded => "succeeded",
@@ -376,11 +400,10 @@ fn open_channel(peer_pubkey: PublicKey, channel_amt_sat: u64, channel_manager: A
 }
 
 fn send_payment(payee: PublicKey, amt_msat: u64, final_cltv: u32, payment_hash: PaymentHash,
-                       payment_secret: Option<PaymentSecret>, payee_features:
-                       Option<InvoiceFeatures>, router: Arc<NetGraphMsgHandler<Arc<dyn
-                       chain::Access>, Arc<FilesystemLogger>>>, channel_manager:
-                       Arc<ChannelManager>, payment_storage: PaymentInfoStorage, logger:
-                       Arc<FilesystemLogger>) {
+                payment_secret: Option<PaymentSecret>, payee_features: Option<InvoiceFeatures>,
+                router: Arc<NetGraphMsgHandler<Arc<dyn chain::Access>, Arc<FilesystemLogger>>>,
+                channel_manager: Arc<ChannelManager>, payment_storage: PaymentInfoStorage, logger:
+                Arc<FilesystemLogger>) {
     let network_graph = router.network_graph.read().unwrap();
     let first_hops = channel_manager.list_usable_channels();
     let payer_pubkey = channel_manager.get_our_node_id();
@@ -403,12 +426,12 @@ fn send_payment(payee: PublicKey, amt_msat: u64, final_cltv: u32, payment_hash:
         }
     };
     let mut payments = payment_storage.lock().unwrap();
-    payments.insert(payment_hash, (None, HTLCDirection::Outbound, status));
+    payments.insert(payment_hash, (None, HTLCDirection::Outbound, status,
+                                   SatoshiAmount(Some(amt_msat * 1000))));
 }
 
 fn get_invoice(amt_sat: u64, payment_storage: PaymentInfoStorage, our_node_privkey: SecretKey,
-                      channel_manager: Arc<ChannelManager>, router: Arc<NetGraphMsgHandler<Arc<dyn
-                      chain::Access>, Arc<FilesystemLogger>>>) {
+               channel_manager: Arc<ChannelManager>, network: Network) {
     let mut payments = payment_storage.lock().unwrap();
     let secp_ctx = Secp256k1::new();
 
@@ -418,54 +441,39 @@ fn get_invoice(amt_sat: u64, payment_storage: PaymentInfoStorage, our_node_privk
 
 
     let our_node_pubkey = channel_manager.get_our_node_id();
-               let invoice = lightning_invoice::InvoiceBuilder::new(match NETWORK {
+               let mut invoice = lightning_invoice::InvoiceBuilder::new(match network {
                                Network::Bitcoin => lightning_invoice::Currency::Bitcoin,
                                Network::Testnet => lightning_invoice::Currency::BitcoinTestnet,
                                Network::Regtest => lightning_invoice::Currency::Regtest,
         Network::Signet => panic!("Signet invoices not supported")
-               }).payment_hash(payment_hash).description("rust-lightning-bitcoinrpc invoice".to_string())
-                               .amount_pico_btc(amt_sat * 10)
+               })
+        .payment_hash(payment_hash).description("rust-lightning-bitcoinrpc invoice".to_string())
+                               .amount_pico_btc(amt_sat * 10_000)
                                .current_timestamp()
         .payee_pub_key(our_node_pubkey);
 
     // Add route hints to the invoice.
-    // let our_channels = channel_manager.list_usable_channels();
-    // let network_graph = router.network_graph.read().unwrap();
-    // let network_channels = network_graph.get_channels();
-    // for channel in our_channels {
-    //     let short_channel_id_opt = channel.short_channel_id;
-    //     if short_channel_id_opt.is_none() {
-    //         continue
-    //     }
-
-    //     let short_channel_id = short_channel_id_opt.unwrap();
-    //     let channel_routing_info_opt = network_channels.get(&short_channel_id);
-    //     if channel_routing_info_opt.is_none() {
-    //         continue
-    //     }
-
-    //     let channel_routing_info = channel_routing_info_opt.unwrap();
-    //     let mut counterparty = channel_routing_info.node_two;
-    //     let mut counterparty_chan_fees_opt = channel_routing_info.one_to_two.as_ref();
-    //     if channel_routing_info.node_two != our_node_pubkey { // e.g. if our counterparty is node_one
-    //         counterparty = channel_routing_info.node_one;
-    //         counterparty_chan_fees_opt = channel_routing_info.two_to_one.as_ref();
-    //     }
-    //     if counterparty_chan_fees_opt.is_none() {
-    //         continue
-    //     }
-
-    //     let counterparty_chan_fees = counterparty_chan_fees_opt.unwrap();
-    //     invoice = invoice.route(vec![
-    //         lightning_invoice::RouteHop {
-    //             short_channel_id: short_channel_id.to_be_bytes(),
-    //             cltv_expiry_delta: counterparty_chan_fees.cltv_expiry_delta,
-    //             fee_base_msat: counterparty_chan_fees.fees.base_msat,
-    //             fee_proportional_millionths: counterparty_chan_fees.fees.proportional_millionths,
-    //             pubkey: counterparty,
-    //         }
-    //     ]);
-    // }
+    let our_channels = channel_manager.list_usable_channels();
+    for channel in our_channels {
+        let short_channel_id = match channel.short_channel_id {
+            Some(id) => id.to_be_bytes(),
+            None => continue
+        };
+        let forwarding_info = match channel.counterparty_forwarding_info {
+            Some(info) => info,
+            None => continue,
+        };
+        println!("VMW: adding routehop, info.fee base: {}", forwarding_info.fee_base_msat);
+        invoice = invoice.route(vec![
+            lightning_invoice::RouteHop {
+                pubkey: channel.remote_network_id,
+                short_channel_id,
+                fee_base_msat: forwarding_info.fee_base_msat,
+                fee_proportional_millionths: forwarding_info.fee_proportional_millionths,
+                cltv_expiry_delta: forwarding_info.cltv_expiry_delta,
+            }
+        ]);
+    }
 
     // Sign the invoice.
     let invoice = invoice.build_signed(|msg_hash| {
@@ -479,7 +487,8 @@ fn get_invoice(amt_sat: u64, payment_storage: PaymentInfoStorage, our_node_privk
 
     payments.insert(PaymentHash(payment_hash.into_inner()), (Some(PaymentPreimage(preimage)),
                                                              HTLCDirection::Inbound,
-                                                             HTLCStatus::Pending));
+                                                             HTLCStatus::Pending,
+                                                             SatoshiAmount(Some(amt_sat))));
 }
 
 fn close_channel(channel_id: [u8; 32], channel_manager: Arc<ChannelManager>) {
index 81e2e959659a6b5f06deda943f73199e75c7a577..cd4ea909ef160b658ca241c110d1521c02e9e7e7 100644 (file)
@@ -63,7 +63,7 @@ pub(crate) fn read_channel_peer_data(path: &Path) -> Result<HashMap<PublicKey, S
 }
 
 
-pub(crate) fn read_channelmonitors_from_disk(path: String, keys_manager: Arc<KeysManager>) ->
+pub(crate) fn read_channelmonitors(path: String, keys_manager: Arc<KeysManager>) ->
     Result<HashMap<OutPoint, (BlockHash, ChannelMonitor<InMemorySigner>)>, std::io::Error>
 {
     if !Path::new(&path).exists() {
index 3c417ef398028c89903b2fc7cd30e2787fb45528..421db95ef833da8142462d3a93f19f01a96df884 100644 (file)
@@ -4,7 +4,7 @@ mod convert;
 mod disk;
 mod hex_utils;
 
-use background_processor::BackgroundProcessor;
+use lightning_background_processor::BackgroundProcessor;
 use bitcoin::BlockHash;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::Transaction;
@@ -39,6 +39,7 @@ use lightning_persister::FilesystemPersister;
 use rand::{thread_rng, Rng};
 use lightning::routing::network_graph::NetGraphMsgHandler;
 use std::collections::HashMap;
+use std::fmt;
 use std::fs;
 use std::fs::File;
 use std::io;
@@ -50,8 +51,6 @@ use std::time::{Duration, SystemTime};
 use tokio::runtime::Runtime;
 use tokio::sync::mpsc;
 
-pub(crate) const NETWORK: Network = Network::Regtest;
-
 #[derive(PartialEq)]
 pub(crate) enum HTLCDirection {
     Inbound,
@@ -64,8 +63,21 @@ pub(crate) enum HTLCStatus {
     Failed,
 }
 
+pub(crate) struct SatoshiAmount(Option<u64>);
+
+impl fmt::Display for SatoshiAmount {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {
+            Some(amt) => write!(f, "{}", amt),
+            None => write!(f, "unknown")
+
+        }
+    }
+}
+
 pub(crate) type PaymentInfoStorage = Arc<Mutex<HashMap<PaymentHash, (Option<PaymentPreimage>,
-                                                                     HTLCDirection, HTLCStatus)>>>;
+                                                                     HTLCDirection, HTLCStatus,
+                                                                     SatoshiAmount)>>>;
 
 type ArcChainMonitor = ChainMonitor<InMemorySigner, Arc<dyn Filter>, Arc<BitcoindClient>,
 Arc<BitcoindClient>, Arc<FilesystemLogger>, Arc<FilesystemPersister>>;
@@ -78,7 +90,8 @@ FilesystemLogger>;
 
 fn handle_ldk_events(peer_manager: Arc<PeerManager>, channel_manager: Arc<ChannelManager>,
                      chain_monitor: Arc<ArcChainMonitor>, bitcoind_client: Arc<BitcoindClient>,
-                     keys_manager: Arc<KeysManager>, payment_storage: PaymentInfoStorage)
+                     keys_manager: Arc<KeysManager>, payment_storage: PaymentInfoStorage,
+                     network: Network)
 {
     let mut pending_txs: HashMap<OutPoint, Transaction> = HashMap::new();
     loop {
@@ -92,7 +105,7 @@ fn handle_ldk_events(peer_manager: Arc<PeerManager>, channel_manager: Arc<Channe
                                                 output_script, .. } => {
                     // Construct the raw transaction with one output, that is paid the amount of the
                     // channel.
-                                                 let addr = WitnessProgram::from_scriptpubkey(&output_script[..], match NETWORK {
+                                                 let addr = WitnessProgram::from_scriptpubkey(&output_script[..], match network {
                                                                  Network::Bitcoin => bitcoin_bech32::constants::Network::Bitcoin,
                                                                  Network::Testnet => bitcoin_bech32::constants::Network::Testnet,
                                                                  Network::Regtest => bitcoin_bech32::constants::Network::Regtest,
@@ -129,31 +142,33 @@ fn handle_ldk_events(peer_manager: Arc<PeerManager>, channel_manager: Arc<Channe
                                        },
                                        Event::PaymentReceived { payment_hash, payment_secret, amt: amt_msat } => {
                     let mut payments = payment_storage.lock().unwrap();
-                    if let Some((Some(preimage), _, _)) = payments.get(&payment_hash) {
+                    if let Some((Some(preimage), _, _, _)) = payments.get(&payment_hash) {
                                                            assert!(loop_channel_manager.claim_funds(preimage.clone(), &payment_secret,
                                                                  amt_msat));
                         println!("\nEVENT: received payment from payment_hash {} of {} satoshis",
                                  hex_utils::hex_str(&payment_hash.0), amt_msat / 1000);
                         print!("> "); io::stdout().flush().unwrap();
-                        let (_, _, ref mut status) = payments.get_mut(&payment_hash).unwrap();
+                        let (_, _, ref mut status, _) = payments.get_mut(&payment_hash).unwrap();
                         *status = HTLCStatus::Succeeded;
                     } else {
                         println!("\nERROR: we received a payment but didn't know the preimage");
                         print!("> "); io::stdout().flush().unwrap();
                         loop_channel_manager.fail_htlc_backwards(&payment_hash, &payment_secret);
-                        payments.insert(payment_hash, (None, HTLCDirection::Inbound, HTLCStatus::Failed));
+                        payments.insert(payment_hash, (None, HTLCDirection::Inbound,
+                                                       HTLCStatus::Failed, SatoshiAmount(None)));
                     }
                                        },
                                        Event::PaymentSent { payment_preimage } => {
                     let hashed = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner());
                     let mut payments = payment_storage.lock().unwrap();
-                    for (payment_hash, (preimage_option, _, status)) in payments.iter_mut() {
+                    for (payment_hash, (preimage_option, _, status, amt_sat)) in payments.iter_mut() {
                         if *payment_hash == hashed {
                             *preimage_option = Some(payment_preimage);
                             *status = HTLCStatus::Succeeded;
-                            println!("\nNEW EVENT: successfully sent payment from payment hash \
-                                         {:?} with preimage {:?}", hex_utils::hex_str(&payment_hash.0),
-                                     hex_utils::hex_str(&payment_preimage.0));
+                            println!("\nNEW EVENT: successfully sent payment of {} satoshis from \
+                                         payment hash {:?} with preimage {:?}", amt_sat,
+                                         hex_utils::hex_str(&payment_hash.0),
+                                         hex_utils::hex_str(&payment_preimage.0));
                             print!("> "); io::stdout().flush().unwrap();
                         }
                     }
@@ -170,7 +185,7 @@ fn handle_ldk_events(peer_manager: Arc<PeerManager>, channel_manager: Arc<Channe
 
                     let mut payments = payment_storage.lock().unwrap();
                     if payments.contains_key(&payment_hash) {
-                        let (_, _, ref mut status) = payments.get_mut(&payment_hash).unwrap();
+                        let (_, _, ref mut status, _) = payments.get_mut(&payment_hash).unwrap();
                         *status = HTLCStatus::Failed;
                     }
                                        },
@@ -186,8 +201,7 @@ fn handle_ldk_events(peer_manager: Arc<PeerManager>, channel_manager: Arc<Channe
                                                                            destination_address.script_pubkey(),
                                                                            tx_feerate, &Secp256k1::new()).unwrap();
                     bitcoind_client.broadcast_transaction(&spending_tx);
-                    // XXX maybe need to rescan and blah? but contrary to what matt's saying, it
-                    // looks like spend_spendable's got us covered
+                    // XXX maybe need to rescan and blah?
                 }
             }
         }
@@ -206,10 +220,15 @@ fn main() {
     fs::create_dir_all(ldk_data_dir.clone()).unwrap();
 
     // Initialize our bitcoind client.
-    let bitcoind_client = Arc::new(BitcoindClient::new(args.bitcoind_rpc_host.clone(),
-                                                       args.bitcoind_rpc_port,
-                                                       args.bitcoind_rpc_username.clone(),
-                                                       args.bitcoind_rpc_password.clone()).unwrap());
+    let bitcoind_client = match BitcoindClient::new(args.bitcoind_rpc_host.clone(),
+                                         args.bitcoind_rpc_port, args.bitcoind_rpc_username.clone(),
+                                         args.bitcoind_rpc_password.clone()) {
+        Ok(client) => Arc::new(client),
+        Err(e) => {
+            println!("Failed to connect to bitcoind client: {}", e);
+            return
+        }
+    };
     let mut bitcoind_rpc_client = bitcoind_client.get_new_rpc_client().unwrap();
 
     // ## Setup
@@ -258,8 +277,8 @@ fn main() {
 
     // Step 7: Read ChannelMonitor state from disk
     let monitors_path = format!("{}/monitors", ldk_data_dir.clone());
-    let mut outpoint_to_channelmonitor = disk::read_channelmonitors_from_disk(monitors_path.to_string(),
-                                                                        keys_manager.clone()).unwrap();
+    let mut outpoint_to_channelmonitor = disk::read_channelmonitors(monitors_path.to_string(),
+                                                                    keys_manager.clone()).unwrap();
 
     // Step 9: Initialize the ChannelManager
     let user_config = UserConfig::default();
@@ -280,7 +299,7 @@ fn main() {
             restarting_node = false;
             let getinfo_resp = bitcoind_client.get_blockchain_info();
             let chain_params = ChainParameters {
-                network: NETWORK,
+                network: args.network,
                 latest_hash: getinfo_resp.latest_blockhash,
                 latest_height: getinfo_resp.latest_height,
             };
@@ -314,7 +333,7 @@ fn main() {
             chain_listeners.push((monitor_listener_info.0,
                                   &mut monitor_listener_info.1 as &mut dyn chain::Listen));
         }
-        chain_tip = Some(runtime.block_on(init::synchronize_listeners(&mut bitcoind_rpc_client, NETWORK,
+        chain_tip = Some(runtime.block_on(init::synchronize_listeners(&mut bitcoind_rpc_client, args.network,
                                                                       &mut cache, chain_listeners)).unwrap());
     }
 
@@ -327,7 +346,7 @@ fn main() {
 
     // Step 13: Optional: Initialize the NetGraphMsgHandler
     // XXX persist routing data
-    let genesis = genesis_block(NETWORK).header.block_hash();
+    let genesis = genesis_block(args.network).header.block_hash();
     let router = Arc::new(NetGraphMsgHandler::new(genesis, None::<Arc<dyn chain::Access>>, logger.clone()));
 
     // Step 14: Initialize the PeerManager
@@ -364,8 +383,9 @@ fn main() {
     }
     let channel_manager_listener = channel_manager.clone();
     let chain_monitor_listener = chain_monitor.clone();
+    let network = args.network;
     runtime.spawn(async move {
-        let chain_poller = poll::ChainPoller::new(&mut bitcoind_rpc_client, NETWORK);
+        let chain_poller = poll::ChainPoller::new(&mut bitcoind_rpc_client, network);
         let chain_listener = (chain_monitor_listener, channel_manager_listener);
         let mut spv_client = SpvClient::new(chain_tip.unwrap(), chain_poller, &mut cache,
                                             &chain_listener);
@@ -401,10 +421,11 @@ fn main() {
     let payment_info: PaymentInfoStorage = Arc::new(Mutex::new(HashMap::new()));
     let payment_info_for_events = payment_info.clone();
     let handle = runtime_handle.clone();
+    let network = args.network;
     thread::spawn(move || {
         handle_ldk_events(peer_manager_event_listener, channel_manager_event_listener,
                           chain_monitor_event_listener, bitcoind_client.clone(),
-                          keys_manager_listener, payment_info_for_events);
+                          keys_manager_listener, payment_info_for_events, network);
     });
 
     // Reconnect to channel peers if possible.
@@ -422,5 +443,5 @@ fn main() {
     // Start the CLI.
     cli::poll_for_user_input(peer_manager.clone(), channel_manager.clone(), router.clone(),
                              payment_info, keys_manager.get_node_secret(), event_ntfn_sender,
-                             ldk_data_dir.clone(), logger.clone(), handle);
+                             ldk_data_dir.clone(), logger.clone(), handle, args.network);
 }