diff --git a/Cargo.lock b/Cargo.lock index be636b6f..581879bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -147,7 +147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" dependencies = [ "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", ] [[package]] @@ -164,9 +164,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bdk_chain" -version = "0.23.2" +version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5d691fd092aacec7e05046b7d04897d58d6d65ed3152cb6cf65dababcfabed" +checksum = "c290eff038799a8ac0c5a82b6160a9ca456baa299a6f22b262c771342d2846c0" dependencies = [ "bdk_core", "bitcoin", @@ -176,9 +176,9 @@ dependencies = [ [[package]] name = "bdk_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbbe4aad0c898bfeb5253c222be3ea3dccfb380a07e72c87e3e4ed6664a6753" +checksum = "cb3028782f6bf14a6df987244333d34e6b272b5a40a53e4879ec2dfd82275a3a" dependencies = [ "bitcoin", "hashbrown 0.14.5", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "bdk_esplora" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f5961444b5f51b9c3937e729a212363d0e4cde6390ded6e01e16292078df4" +checksum = "83986307ea92997c3d051e8c306af8115a05add601e22acb7c1903008e6b614e" dependencies = [ "async-trait", "bdk_core", @@ -209,9 +209,9 @@ dependencies = [ [[package]] name = "bdk_wallet" -version = "2.3.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03f1e31ccc562f600981f747d2262b84428cbff52c9c9cdf14d15fb15bd2286" +checksum = "1284fb23acc3e3022673712b55f4d5ce7e38aadc2c49bbef830dc3935f0a3289" dependencies = [ "bdk_chain", "bip39", @@ -240,11 +240,11 @@ dependencies = [ [[package]] name = "bip39" -version = "2.2.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d193de1f7487df1914d3a568b772458861d33f9c54249612cc2893d6915054" +checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand 0.8.5", "rand_core 0.6.4", "serde", @@ -253,36 +253,44 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.32.7" +version = "0.32.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" +checksum = "a1a121ccf1177a09084bd6ce97c52119919aac08ea3649967958eae41beceebf" dependencies = [ "base58ck", "base64 0.21.7", "bech32", - "bitcoin-internals 0.3.0", "bitcoin-io", "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", + "bitcoin_hashes", + "hex-conservative 0.2.2", "hex_lit", "secp256k1", "serde", ] [[package]] -name = "bitcoin-internals" -version = "0.2.0" +name = "bitcoin-consensus-encoding" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +checksum = "b2d6094e2a1ba3c93b5a596fe5a10d1a10c3c6e06785cde89f693a044c01aa40" +dependencies = [ + "bitcoin-internals 0.5.0", +] [[package]] name = "bitcoin-internals" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" dependencies = [ - "serde", + "hex-conservative 0.3.2", ] [[package]] @@ -305,24 +313,14 @@ dependencies = [ [[package]] name = "bitcoin-units" -version = "0.1.2" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +checksum = "9cb95693f371d089a4b5b6fc41c6f3ea6e01ee8c15388335dfac8ea685173b51" dependencies = [ - "bitcoin-internals 0.3.0", + "bitcoin-consensus-encoding", "serde", ] -[[package]] -name = "bitcoin_hashes" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" -dependencies = [ - "bitcoin-internals 0.2.0", - "hex-conservative 0.1.2", -] - [[package]] name = "bitcoin_hashes" version = "0.14.0" @@ -330,7 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" dependencies = [ "bitcoin-io", - "hex-conservative 0.2.1", + "hex-conservative 0.2.2", "serde", ] @@ -520,7 +518,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec4f825369fc7134da70ca4040fddc8e03b80a46d249ae38d9c1c39b7b4476bf" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "tokio", ] @@ -580,15 +578,16 @@ dependencies = [ [[package]] name = "esplora-client" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0af349d96a5d9ad77ba59f1437aa6f348b03c5865d4f7d6e7a662d60aedce39" +checksum = "f19e3ea99dbfbef0c1ec26d83e69de0c579f6aa6aaac4f44597805fcc27e97af" dependencies = [ "bitcoin", - "hex-conservative 0.2.1", + "hex-conservative 0.2.2", "log", "reqwest 0.12.24", "serde", + "serde_json", "tokio", ] @@ -848,15 +847,18 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hex-conservative" -version = "0.1.2" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +dependencies = [ + "arrayvec", +] [[package]] name = "hex-conservative" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" dependencies = [ "arrayvec", ] @@ -1052,7 +1054,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.1", "tokio", "tower-service", "tracing", @@ -1264,7 +1266,7 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "ldk-node" version = "0.8.0+git" -source = "git+https://github.com/lightningdevkit/ldk-node?rev=00dba456a10cb60172eaa74e0a8b11c5e0473dcc#00dba456a10cb60172eaa74e0a8b11c5e0473dcc" +source = "git+https://github.com/lightningdevkit/ldk-node?rev=f2e44fdd21490ff3fa90445d7a28b19cfd020c3d#f2e44fdd21490ff3fa90445d7a28b19cfd020c3d" dependencies = [ "async-trait", "base64 0.22.1", @@ -1315,7 +1317,7 @@ dependencies = [ "clap", "futures-util", "getrandom 0.2.16", - "hex-conservative 0.2.1", + "hex-conservative 0.2.2", "http-body-util", "hyper 1.7.0", "hyper-util", @@ -1337,7 +1339,7 @@ version = "0.1.0" dependencies = [ "clap", "clap_complete", - "hex-conservative 0.2.1", + "hex-conservative 0.2.2", "ldk-server-client", "serde", "serde_json", @@ -1349,8 +1351,8 @@ dependencies = [ name = "ldk-server-client" version = "0.1.0" dependencies = [ - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", + "bitcoin_hashes", + "hex-conservative 0.2.2", "hyper 0.14.32", "hyper-rustls 0.24.2", "ldk-server-grpc", @@ -1385,7 +1387,7 @@ dependencies = [ name = "ldk-server-mcp" version = "0.1.0" dependencies = [ - "hex-conservative 0.2.1", + "hex-conservative 0.2.2", "ldk-server-client", "serde", "serde_json", @@ -1439,7 +1441,7 @@ source = "git+https://github.com/lightningdevkit/rust-lightning?rev=3dfcc4cca186 dependencies = [ "bitcoin", "bitcoin-io", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "lightning", "lightning-liquidity", "lightning-rapid-gossip-sync", @@ -1534,7 +1536,7 @@ source = "git+https://github.com/lightningdevkit/rust-lightning?rev=3dfcc4cca186 dependencies = [ "bitcoin", "bitcoin-io", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "lightning", ] @@ -1822,7 +1824,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.34", - "socket2 0.5.10", + "socket2 0.6.1", "thiserror", "tokio", "tracing", @@ -1859,7 +1861,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.1", "tracing", "windows-sys 0.60.2", ] @@ -2203,7 +2205,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "rand 0.8.5", "secp256k1-sys", "serde", @@ -2772,14 +2774,14 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vss-client-ng" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6334cb4940aba86a2e2aa9dde7c722a2510f55815422088a2a2ac24f46579e6a" +checksum = "49dae7224f498977c17c2ac85d5377d6a2b7290102add15070db257b86a519d6" dependencies = [ "async-trait", "base64 0.22.1", "bitcoin", - "bitcoin_hashes 0.14.0", + "bitcoin_hashes", "bitreq", "chacha20-poly1305 0.1.2", "log", diff --git a/ldk-server/Cargo.toml b/ldk-server/Cargo.toml index d82bab19..d27e4943 100644 --- a/ldk-server/Cargo.toml +++ b/ldk-server/Cargo.toml @@ -13,7 +13,7 @@ keywords = ["bitcoin", "lightning", "ldk", "server"] categories = ["cryptography::cryptocurrencies"] [dependencies] -ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "00dba456a10cb60172eaa74e0a8b11c5e0473dcc" } +ldk-node = { git = "https://github.com/lightningdevkit/ldk-node", rev = "f2e44fdd21490ff3fa90445d7a28b19cfd020c3d" } serde = { version = "1.0.203", default-features = false, features = ["derive"] } hyper = { version = "1", default-features = false, features = ["server", "http2"] } http-body-util = { version = "0.1", default-features = false } diff --git a/ldk-server/src/main.rs b/ldk-server/src/main.rs index 9159057b..123c35fb 100644 --- a/ldk-server/src/main.rs +++ b/ldk-server/src/main.rs @@ -25,7 +25,7 @@ use hex::DisplayHex; use hyper::server::conn::http2; use hyper_util::rt::{TokioExecutor, TokioIo}; use ldk_node::bitcoin::Network; -use ldk_node::config::Config; +use ldk_node::config::{Config, ElectrumSyncConfig, EsploraSyncConfig}; use ldk_node::lightning::events::ClosureReason; use ldk_node::lightning::ln::channelmanager::PaymentId; use ldk_node::lightning::ln::types::ChannelId; @@ -168,14 +168,34 @@ fn main() { } match config_file.chain_source { - ChainSource::Rpc { rpc_host, rpc_port, rpc_user, rpc_password } => { - builder.set_chain_source_bitcoind_rpc(rpc_host, rpc_port, rpc_user, rpc_password); + ChainSource::Rpc { + rpc_host, + rpc_port, + rpc_user, + rpc_password, + wallet_rescan_from_height, + } => { + builder.set_chain_source_bitcoind_rpc( + rpc_host, + rpc_port, + rpc_user, + rpc_password, + wallet_rescan_from_height, + ); }, - ChainSource::Electrum { server_url } => { - builder.set_chain_source_electrum(server_url, None); + ChainSource::Electrum { server_url, force_wallet_full_scan } => { + let sync_config = force_wallet_full_scan.then(|| ElectrumSyncConfig { + force_wallet_full_scan: true, + ..ElectrumSyncConfig::default() + }); + builder.set_chain_source_electrum(server_url, sync_config); }, - ChainSource::Esplora { server_url } => { - builder.set_chain_source_esplora(server_url, None); + ChainSource::Esplora { server_url, force_wallet_full_scan } => { + let sync_config = force_wallet_full_scan.then(|| EsploraSyncConfig { + force_wallet_full_scan: true, + ..EsploraSyncConfig::default() + }); + builder.set_chain_source_esplora(server_url, sync_config); }, } @@ -193,10 +213,11 @@ fn main() { } if let Some(lsps2_client_config) = config_file.lsps2_client_config { - builder.set_liquidity_source_lsps2( + builder.add_liquidity_source( lsps2_client_config.node_id, lsps2_client_config.address, lsps2_client_config.token, + false, ); } @@ -210,7 +231,7 @@ fn main() { // LSPS2 support is highly experimental and for testing purposes only. #[cfg(feature = "experimental-lsps2-support")] - builder.set_liquidity_provider_lsps2( + builder.enable_liquidity_provider( config_file.lsps2_service_config.expect("Missing liquidity.lsps2_server config"), ); diff --git a/ldk-server/src/util/config.rs b/ldk-server/src/util/config.rs index dbedca92..fc2ee45b 100644 --- a/ldk-server/src/util/config.rs +++ b/ldk-server/src/util/config.rs @@ -89,9 +89,21 @@ pub struct TlsConfig { #[derive(Debug, PartialEq, Eq)] pub enum ChainSource { - Rpc { rpc_host: String, rpc_port: u16, rpc_user: String, rpc_password: String }, - Electrum { server_url: String }, - Esplora { server_url: String }, + Rpc { + rpc_host: String, + rpc_port: u16, + rpc_user: String, + rpc_password: String, + wallet_rescan_from_height: Option, + }, + Electrum { + server_url: String, + force_wallet_full_scan: bool, + }, + Esplora { + server_url: String, + force_wallet_full_scan: bool, + }, } #[derive(Debug, PartialEq, Eq)] @@ -114,6 +126,8 @@ struct ConfigBuilder { bitcoind_rpc_address: Option, bitcoind_rpc_user: Option, bitcoind_rpc_password: Option, + rescan_from_height: Option, + force_wallet_full_scan: bool, rgs_server_url: Option, lsps2: Option, log_level: Option, @@ -242,6 +256,14 @@ impl ConfigBuilder { self.bitcoind_rpc_password = Some(bitcoind_rpc_password.clone()); } + if let Some(rescan_from_height) = args.rescan_from_height { + self.rescan_from_height = Some(rescan_from_height); + } + + if args.force_wallet_full_scan { + self.force_wallet_full_scan = true; + } + if let Some(storage_dir_path) = &args.storage_dir_path { self.storage_dir_path = Some(storage_dir_path.clone()); } @@ -363,6 +385,13 @@ impl ConfigBuilder { } let chain_source = if rpc_configured { + if self.force_wallet_full_scan { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "`--force-wallet-full-scan` requires the Electrum or Esplora chain source.", + )); + } + let rpc_address = self .bitcoind_rpc_address .ok_or_else(|| missing_field_err("bitcoind_rpc_address"))?; @@ -375,11 +404,35 @@ impl ConfigBuilder { .bitcoind_rpc_password .ok_or_else(|| missing_field_err("bitcoind_rpc_password"))?; - ChainSource::Rpc { rpc_host, rpc_port, rpc_user, rpc_password } + ChainSource::Rpc { + rpc_host, + rpc_port, + rpc_user, + rpc_password, + wallet_rescan_from_height: self.rescan_from_height, + } } else if let Some(url) = self.electrum_url { - ChainSource::Electrum { server_url: url } + if self.rescan_from_height.is_some() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "`--rescan-from-height` requires the bitcoind RPC chain source.", + )); + } + ChainSource::Electrum { + server_url: url, + force_wallet_full_scan: self.force_wallet_full_scan, + } } else if let Some(url) = self.esplora_url { - ChainSource::Esplora { server_url: url } + if self.rescan_from_height.is_some() { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "`--rescan-from-height` requires the bitcoind RPC chain source.", + )); + } + ChainSource::Esplora { + server_url: url, + force_wallet_full_scan: self.force_wallet_full_scan, + } } else { return Err(io::Error::new(io::ErrorKind::InvalidInput, "No valid Chain Source configured. Provide Bitcoind RPC, Electrum, or Esplora details.")); }; @@ -883,6 +936,20 @@ pub struct ArgsConfig { )] bitcoind_rpc_password: Option, + #[arg( + long, + env = "LDK_SERVER_RESCAN_FROM_HEIGHT", + help = "Rescan the wallet from this block height on first startup. Only supported with the bitcoind RPC chain source." + )] + rescan_from_height: Option, + + #[arg( + long, + env = "LDK_SERVER_FORCE_WALLET_FULL_SCAN", + help = "Force wallet full scans until one succeeds. Only supported with Electrum and Esplora chain sources." + )] + force_wallet_full_scan: bool, + #[arg( long, env = "LDK_SERVER_STORAGE_DIR_PATH", @@ -1075,6 +1142,8 @@ mod tests { bitcoind_rpc_address: Some(String::from("127.0.1.9:18443")), bitcoind_rpc_user: Some(String::from("bitcoind-testuser_cli")), bitcoind_rpc_password: Some(String::from("bitcoind-testpassword_cli")), + rescan_from_height: None, + force_wallet_full_scan: false, storage_dir_path: Some(String::from("/tmp_cli")), node_alias: Some(String::from("LDK Server CLI")), pathfinding_scores_source_url: Some(String::from("https://example.com/")), @@ -1102,6 +1171,8 @@ mod tests { bitcoind_rpc_address: None, bitcoind_rpc_user: None, bitcoind_rpc_password: None, + rescan_from_height: None, + force_wallet_full_scan: false, storage_dir_path: None, pathfinding_scores_source_url: None, node_async_payments_role: None, @@ -1124,6 +1195,29 @@ mod tests { ) } + fn lsps2_service_config_for_feature() -> &'static str { + #[cfg(feature = "experimental-lsps2-support")] + { + r#" + [liquidity.lsps2_service] + advertise_service = false + channel_opening_fee_ppm = 1000 + channel_over_provisioning_ppm = 500000 + min_channel_opening_fee_msat = 10000000 + min_channel_lifetime = 4320 + max_client_to_self_delay = 1440 + min_payment_size_msat = 10000000 + max_payment_size_msat = 25000000000 + client_trusts_lsp = true + disable_client_reserve = false + "# + } + #[cfg(not(feature = "experimental-lsps2-support"))] + { + "" + } + } + #[test] fn test_config_from_file() { let storage_path = std::env::temp_dir(); @@ -1156,6 +1250,7 @@ mod tests { rpc_port: 8332, rpc_user: "bitcoind-testuser".to_string(), rpc_password: "bitcoind-testpassword".to_string(), + wallet_rescan_from_height: None, }, rgs_server_url: Some("https://rapidsync.lightningdevkit.org/snapshot/v2/".to_string()), lsps2_client_config: Some(LSPSClientConfig { @@ -1261,11 +1356,13 @@ mod tests { fs::write(storage_path.join(config_file_name), toml_config).unwrap(); let config = load_config(&args_config).unwrap(); - let ChainSource::Electrum { server_url } = config.chain_source else { + let ChainSource::Electrum { server_url, force_wallet_full_scan } = config.chain_source + else { panic!("unexpected chain source"); }; assert_eq!(server_url, "ssl://electrum.blockstream.info:50002"); + assert!(!force_wallet_full_scan); // Test case where only bitcoind is set @@ -1315,7 +1412,13 @@ mod tests { fs::write(storage_path.join(config_file_name), toml_config).unwrap(); let config = load_config(&args_config).unwrap(); - let ChainSource::Rpc { rpc_host, rpc_port, rpc_user, rpc_password } = config.chain_source + let ChainSource::Rpc { + rpc_host, + rpc_port, + rpc_user, + rpc_password, + wallet_rescan_from_height, + } = config.chain_source else { panic!("unexpected chain source"); }; @@ -1324,6 +1427,7 @@ mod tests { assert_eq!(rpc_port, 8332); assert_eq!(rpc_user, "bitcoind-testuser"); assert_eq!(rpc_password, "bitcoind-testpassword"); + assert_eq!(wallet_rescan_from_height, None); // Test case where both bitcoind and esplora are set, resulting in an error @@ -1570,6 +1674,7 @@ mod tests { rpc_port: port, rpc_user: args_config.bitcoind_rpc_user.unwrap(), rpc_password: args_config.bitcoind_rpc_password.unwrap(), + wallet_rescan_from_height: None, }, rgs_server_url: None, lsps2_client_config: None, @@ -1669,6 +1774,7 @@ mod tests { rpc_port: port, rpc_user: args_config.bitcoind_rpc_user.unwrap(), rpc_password: args_config.bitcoind_rpc_password.unwrap(), + wallet_rescan_from_height: None, }, rgs_server_url: Some("https://rapidsync.lightningdevkit.org/snapshot/v2/".to_string()), lsps2_client_config: Some(LSPSClientConfig { @@ -2055,4 +2161,143 @@ mod tests { assert!(mnemonic_result.is_err()); assert!(seed_result.is_err()); } + + #[test] + fn test_accepts_rescan_from_height_arg() { + let args_config = + ArgsConfig::try_parse_from(["ldk-server", "--rescan-from-height", "144"]).unwrap(); + + assert_eq!(args_config.rescan_from_height, Some(144)); + } + + #[test] + fn test_rescan_from_height_configures_bitcoind() { + let storage_path = std::env::temp_dir(); + let config_file_name = "test_rescan_from_height_bitcoind.toml"; + let toml_config = format!( + r#" + [node] + network = "regtest" + + [bitcoind] + rpc_address = "127.0.0.1:8332" + rpc_user = "bitcoind-testuser" + rpc_password = "bitcoind-testpassword" + {} + "#, + lsps2_service_config_for_feature() + ); + + fs::write(storage_path.join(config_file_name), toml_config).unwrap(); + let mut args_config = empty_args_config(); + args_config.config_file = + Some(storage_path.join(config_file_name).to_string_lossy().to_string()); + args_config.rescan_from_height = Some(144); + + let config = load_config(&args_config).unwrap(); + let ChainSource::Rpc { wallet_rescan_from_height, .. } = config.chain_source else { + panic!("unexpected chain source"); + }; + + assert_eq!(wallet_rescan_from_height, Some(144)); + } + + #[test] + fn test_rescan_from_height_rejects_non_bitcoind_chain_sources() { + for (config_file_name, chain_config) in [ + ( + "test_rescan_from_height_rejects_electrum.toml", + r#" + [node] + network = "regtest" + + [electrum] + server_url = "ssl://electrum.blockstream.info:50002" + "#, + ), + ( + "test_rescan_from_height_rejects_esplora.toml", + r#" + [node] + network = "regtest" + + [esplora] + server_url = "https://mempool.space/api" + "#, + ), + ] { + let storage_path = std::env::temp_dir(); + fs::write(storage_path.join(config_file_name), chain_config).unwrap(); + let mut args_config = empty_args_config(); + args_config.config_file = + Some(storage_path.join(config_file_name).to_string_lossy().to_string()); + args_config.rescan_from_height = Some(144); + + let err = load_config(&args_config).unwrap_err(); + assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + assert!(err.to_string().contains("--rescan-from-height")); + } + } + + #[test] + fn test_accepts_force_wallet_full_scan_arg() { + let args_config = + ArgsConfig::try_parse_from(["ldk-server", "--force-wallet-full-scan"]).unwrap(); + + assert!(args_config.force_wallet_full_scan); + } + + #[test] + fn test_force_wallet_full_scan_configures_electrum_and_esplora() { + for (config_file_name, chain_config) in [ + ( + "test_force_wallet_full_scan_electrum.toml", + r#" + [node] + network = "regtest" + + [electrum] + server_url = "ssl://electrum.blockstream.info:50002" + "#, + ), + ( + "test_force_wallet_full_scan_esplora.toml", + r#" + [node] + network = "regtest" + + [esplora] + server_url = "https://mempool.space/api" + "#, + ), + ] { + let storage_path = std::env::temp_dir(); + let chain_config = format!("{}{}", chain_config, lsps2_service_config_for_feature()); + fs::write(storage_path.join(config_file_name), chain_config).unwrap(); + let mut args_config = empty_args_config(); + args_config.config_file = + Some(storage_path.join(config_file_name).to_string_lossy().to_string()); + args_config.force_wallet_full_scan = true; + + let config = load_config(&args_config).unwrap(); + let force_wallet_full_scan = match config.chain_source { + ChainSource::Electrum { force_wallet_full_scan, .. } + | ChainSource::Esplora { force_wallet_full_scan, .. } => force_wallet_full_scan, + ChainSource::Rpc { .. } => panic!("unexpected chain source"), + }; + + assert!(force_wallet_full_scan); + } + } + + #[test] + fn test_force_wallet_full_scan_rejects_bitcoind() { + let mut args_config = default_args_config(); + args_config.force_wallet_full_scan = true; + + let err = load_config(&args_config).unwrap_err(); + + assert_eq!(err.kind(), io::ErrorKind::InvalidInput); + assert!(err.to_string().contains("--force-wallet-full-scan")); + } } diff --git a/ldk-server/src/util/proto_adapter.rs b/ldk-server/src/util/proto_adapter.rs index 7c94453d..42c3738c 100644 --- a/ldk-server/src/util/proto_adapter.rs +++ b/ldk-server/src/util/proto_adapter.rs @@ -53,9 +53,11 @@ pub(crate) fn peer_to_proto(peer: PeerDetails) -> Peer { } pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { + let counterparty = channel.counterparty; + Channel { channel_id: channel.channel_id.0.to_lower_hex_string(), - counterparty_node_id: channel.counterparty_node_id.to_string(), + counterparty_node_id: counterparty.node_id.to_string(), funding_txo: channel .funding_txo .map(|o| OutPoint { txid: o.txid.to_string(), vout: o.vout }), @@ -75,17 +77,21 @@ pub(crate) fn channel_to_proto(channel: ChannelDetails) -> Channel { next_outbound_htlc_limit_msat: channel.next_outbound_htlc_limit_msat, next_outbound_htlc_minimum_msat: channel.next_outbound_htlc_minimum_msat, force_close_spend_delay: channel.force_close_spend_delay.map(|x| x as u32), - counterparty_outbound_htlc_minimum_msat: channel.counterparty_outbound_htlc_minimum_msat, - counterparty_outbound_htlc_maximum_msat: channel.counterparty_outbound_htlc_maximum_msat, - counterparty_unspendable_punishment_reserve: channel - .counterparty_unspendable_punishment_reserve, - counterparty_forwarding_info_fee_base_msat: channel - .counterparty_forwarding_info_fee_base_msat, - counterparty_forwarding_info_fee_proportional_millionths: channel - .counterparty_forwarding_info_fee_proportional_millionths, - counterparty_forwarding_info_cltv_expiry_delta: channel - .counterparty_forwarding_info_cltv_expiry_delta - .map(|x| x as u32), + counterparty_outbound_htlc_minimum_msat: counterparty.outbound_htlc_minimum_msat, + counterparty_outbound_htlc_maximum_msat: counterparty.outbound_htlc_maximum_msat, + counterparty_unspendable_punishment_reserve: counterparty.unspendable_punishment_reserve, + counterparty_forwarding_info_fee_base_msat: counterparty + .forwarding_info + .as_ref() + .map(|info| info.fee_base_msat), + counterparty_forwarding_info_fee_proportional_millionths: counterparty + .forwarding_info + .as_ref() + .map(|info| info.fee_proportional_millionths), + counterparty_forwarding_info_cltv_expiry_delta: counterparty + .forwarding_info + .as_ref() + .map(|info| info.cltv_expiry_delta as u32), } } @@ -150,7 +156,7 @@ pub(crate) fn payment_kind_to_proto( payment_kind: PaymentKind, ) -> ldk_server_grpc::types::PaymentKind { match payment_kind { - PaymentKind::Onchain { txid, status } => ldk_server_grpc::types::PaymentKind { + PaymentKind::Onchain { txid, status, .. } => ldk_server_grpc::types::PaymentKind { kind: Some(Onchain(ldk_server_grpc::types::Onchain { txid: txid.to_string(), status: Some(confirmation_status_to_proto(status)),