From: Elias Rohrer Date: Tue, 14 Nov 2023 07:52:20 +0000 (+0100) Subject: Merge pull request #123 from TheBlueMatt/main X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=5b81f38a91bf0c58ffaadae1a50e794a56b1945b;hp=941cab58328135a750edac6f2c46259d715bc0f8;p=ldk-sample Merge pull request #123 from TheBlueMatt/main Upgrade to LDK 0.0.118 --- diff --git a/Cargo.lock b/Cargo.lock index cb154ee..454cddb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,12 +181,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" - [[package]] name = "iana-time-zone" version = "0.1.53" @@ -235,7 +229,6 @@ dependencies = [ "bitcoin", "bitcoin-bech32", "chrono", - "hex", "libc", "lightning", "lightning-background-processor", diff --git a/Cargo.toml b/Cargo.toml index d73ce6d..dac94fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,19 +8,18 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lightning = { version = "0.0.117", features = ["max_level_trace"] } -lightning-block-sync = { version = "0.0.117", features = [ "rpc-client", "tokio" ] } -lightning-invoice = { version = "0.25.0" } -lightning-net-tokio = { version = "0.0.117" } -lightning-persister = { version = "0.0.117" } -lightning-background-processor = { version = "0.0.117", features = [ "futures" ] } -lightning-rapid-gossip-sync = { version = "0.0.117" } +lightning = { version = "0.0.118", features = ["max_level_trace"] } +lightning-block-sync = { version = "0.0.118", features = [ "rpc-client", "tokio" ] } +lightning-invoice = { version = "0.26.0" } +lightning-net-tokio = { version = "0.0.118" } +lightning-persister = { version = "0.0.118" } +lightning-background-processor = { version = "0.0.118", features = [ "futures" ] } +lightning-rapid-gossip-sync = { version = "0.0.118" } base64 = "0.13.0" bitcoin = "0.29.0" bitcoin-bech32 = "0.12" bech32 = "0.8" -hex = "0.3" libc = "0.2" chrono = { version = "0.4", default-features = false, features = ["clock"] } diff --git a/src/bitcoind_client.rs b/src/bitcoind_client.rs index 9f28015..17ea74c 100644 --- a/src/bitcoind_client.rs +++ b/src/bitcoind_client.rs @@ -15,7 +15,6 @@ use bitcoin::{OutPoint, Script, TxOut, WPubkeyHash, XOnlyPublicKey}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::events::bump_transaction::{Utxo, WalletSource}; use lightning::log_error; -use lightning::routing::utxo::{UtxoLookup, UtxoResult}; use lightning::util::logger::Logger; use lightning_block_sync::http::HttpEndpoint; use lightning_block_sync::rpc::RpcClient; @@ -76,10 +75,23 @@ impl BitcoindClient { "Failed to make initial call to bitcoind - please check your RPC user/password and access settings") })?; let mut fees: HashMap = HashMap::new(); - fees.insert(ConfirmationTarget::MempoolMinimum, AtomicU32::new(MIN_FEERATE)); - fees.insert(ConfirmationTarget::Background, AtomicU32::new(MIN_FEERATE)); - fees.insert(ConfirmationTarget::Normal, AtomicU32::new(2000)); - fees.insert(ConfirmationTarget::HighPriority, AtomicU32::new(5000)); + fees.insert(ConfirmationTarget::OnChainSweep, AtomicU32::new(5000)); + fees.insert( + ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee, + AtomicU32::new(25 * 250), + ); + fees.insert( + ConfirmationTarget::MinAllowedAnchorChannelRemoteFee, + AtomicU32::new(MIN_FEERATE), + ); + fees.insert( + ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee, + AtomicU32::new(MIN_FEERATE), + ); + fees.insert(ConfirmationTarget::AnchorChannelFee, AtomicU32::new(MIN_FEERATE)); + fees.insert(ConfirmationTarget::NonAnchorChannelFee, AtomicU32::new(2000)); + fees.insert(ConfirmationTarget::ChannelCloseMinimum, AtomicU32::new(MIN_FEERATE)); + let client = Self { bitcoind_rpc_client: Arc::new(bitcoind_rpc_client), host, @@ -163,18 +175,28 @@ impl BitcoindClient { } }; - fees.get(&ConfirmationTarget::MempoolMinimum) + fees.get(&ConfirmationTarget::OnChainSweep) + .unwrap() + .store(high_prio_estimate, Ordering::Release); + fees.get(&ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee) + .unwrap() + .store(std::cmp::max(25 * 250, high_prio_estimate * 10), Ordering::Release); + fees.get(&ConfirmationTarget::MinAllowedAnchorChannelRemoteFee) .unwrap() .store(mempoolmin_estimate, Ordering::Release); - fees.get(&ConfirmationTarget::Background) + fees.get(&ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee) + .unwrap() + .store(background_estimate - 250, Ordering::Release); + fees.get(&ConfirmationTarget::AnchorChannelFee) .unwrap() .store(background_estimate, Ordering::Release); - fees.get(&ConfirmationTarget::Normal) + fees.get(&ConfirmationTarget::NonAnchorChannelFee) .unwrap() .store(normal_estimate, Ordering::Release); - fees.get(&ConfirmationTarget::HighPriority) + fees.get(&ConfirmationTarget::ChannelCloseMinimum) .unwrap() - .store(high_prio_estimate, Ordering::Release); + .store(background_estimate, Ordering::Release); + tokio::time::sleep(Duration::from_secs(60)).await; } }); @@ -204,7 +226,8 @@ impl BitcoindClient { // LDK gives us feerates in satoshis per KW but Bitcoin Core here expects fees // denominated in satoshis per vB. First we need to multiply by 4 to convert weight // units to virtual bytes, then divide by 1000 to convert KvB to vB. - "fee_rate": self.get_est_sat_per_1000_weight(ConfirmationTarget::Normal) as f64 / 250.0, + "fee_rate": self + .get_est_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee) as f64 / 250.0, // While users could "cancel" a channel open by RBF-bumping and paying back to // themselves, we don't allow it here as its easy to have users accidentally RBF bump // and pay to the channel funding address, which results in loss of funds. Real @@ -296,13 +319,6 @@ impl BroadcasterInterface for BitcoindClient { } } -impl UtxoLookup for BitcoindClient { - fn get_utxo(&self, _genesis_hash: &BlockHash, _short_channel_id: u64) -> UtxoResult { - // P2PGossipSync takes None for a UtxoLookup, so this will never be called. - todo!(); - } -} - impl WalletSource for BitcoindClient { fn list_confirmed_utxos(&self) -> Result, ()> { let utxos = tokio::task::block_in_place(move || { diff --git a/src/cli.rs b/src/cli.rs index 66af9ee..1856cbd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,8 +1,8 @@ use crate::disk::{self, INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME}; use crate::hex_utils; use crate::{ - ChannelManager, HTLCStatus, MillisatAmount, NetworkGraph, OnionMessenger, PaymentInfo, - PaymentInfoStorage, PeerManager, + ChannelManager, HTLCStatus, InboundPaymentInfoStorage, MillisatAmount, NetworkGraph, + OnionMessenger, OutboundPaymentInfoStorage, PaymentInfo, PeerManager, }; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; @@ -12,7 +12,7 @@ use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry}; use lightning::ln::msgs::SocketAddress; use lightning::ln::{ChannelId, PaymentHash, PaymentPreimage}; use lightning::onion_message::OnionMessagePath; -use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents}; +use lightning::onion_message::{Destination, OnionMessageContents}; use lightning::routing::gossip::NodeId; use lightning::routing::router::{PaymentParameters, RouteParameters}; use lightning::sign::{EntropySource, KeysManager}; @@ -48,7 +48,7 @@ struct UserOnionMessageContents { data: Vec, } -impl CustomOnionMessageContents for UserOnionMessageContents { +impl OnionMessageContents for UserOnionMessageContents { fn tlv_type(&self) -> u64 { self.tlv_type } @@ -63,9 +63,9 @@ impl Writeable for UserOnionMessageContents { pub(crate) fn poll_for_user_input( peer_manager: Arc, channel_manager: Arc, keys_manager: Arc, network_graph: Arc, - onion_messenger: Arc, inbound_payments: Arc>, - outbound_payments: Arc>, ldk_data_dir: String, network: Network, - logger: Arc, fs_store: Arc, + onion_messenger: Arc, inbound_payments: Arc>, + outbound_payments: Arc>, ldk_data_dir: String, + network: Network, logger: Arc, fs_store: Arc, ) { println!( "LDK startup successful. Enter \"help\" to view available commands. Press Ctrl-D to quit." @@ -445,7 +445,7 @@ pub(crate) fn poll_for_user_input( let message_path = OnionMessagePath { intermediate_nodes, destination }; match onion_messenger.send_onion_message( message_path, - OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }), + UserOnionMessageContents { tlv_type, data }, None, ) { Ok(()) => println!("SUCCESS: forwarded onion message to first hop"), @@ -553,7 +553,9 @@ fn list_channels(channel_manager: &Arc, network_graph: &Arc, + outbound_payments: &mut OutboundPaymentInfoStorage, fs_store: Arc, ) { - let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner()); + let payment_id = PaymentId((*invoice.payment_hash()).into_inner()); let payment_secret = Some(*invoice.payment_secret()); outbound_payments.payments.insert( - payment_hash, + payment_id, PaymentInfo { preimage: None, secret: payment_secret, @@ -708,7 +710,7 @@ fn send_payment( Err(e) => { println!("ERROR: failed to send payment: {:?}", e); print!("> "); - outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed; + outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); } }; @@ -716,17 +718,17 @@ fn send_payment( fn keysend( channel_manager: &ChannelManager, payee_pubkey: PublicKey, amt_msat: u64, entropy_source: &E, - outbound_payments: &mut PaymentInfoStorage, fs_store: Arc, + outbound_payments: &mut OutboundPaymentInfoStorage, fs_store: Arc, ) { let payment_preimage = PaymentPreimage(entropy_source.get_secure_random_bytes()); - let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()); + let payment_id = PaymentId(Sha256::hash(&payment_preimage.0[..]).into_inner()); let route_params = RouteParameters::from_payment_params_and_value( PaymentParameters::for_keysend(payee_pubkey, 40, false), amt_msat, ); outbound_payments.payments.insert( - payment_hash, + payment_id, PaymentInfo { preimage: None, secret: None, @@ -738,7 +740,7 @@ fn keysend( match channel_manager.send_spontaneous_payment_with_retry( Some(payment_preimage), RecipientOnionFields::spontaneous_empty(), - PaymentId(payment_hash.0), + payment_id, route_params, Retry::Timeout(Duration::from_secs(10)), ) { @@ -749,16 +751,16 @@ fn keysend( Err(e) => { println!("ERROR: failed to send payment: {:?}", e); print!("> "); - outbound_payments.payments.get_mut(&payment_hash).unwrap().status = HTLCStatus::Failed; + outbound_payments.payments.get_mut(&payment_id).unwrap().status = HTLCStatus::Failed; fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound_payments.encode()).unwrap(); } }; } fn get_invoice( - amt_msat: u64, inbound_payments: &mut PaymentInfoStorage, channel_manager: &ChannelManager, - keys_manager: Arc, network: Network, expiry_secs: u32, - logger: Arc, + amt_msat: u64, inbound_payments: &mut InboundPaymentInfoStorage, + channel_manager: &ChannelManager, keys_manager: Arc, network: Network, + expiry_secs: u32, logger: Arc, ) { let currency = match network { Network::Bitcoin => Currency::Bitcoin, diff --git a/src/disk.rs b/src/disk.rs index a69fdef..d301180 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -1,4 +1,4 @@ -use crate::{cli, NetworkGraph, PaymentInfoStorage}; +use crate::{cli, InboundPaymentInfoStorage, NetworkGraph, OutboundPaymentInfoStorage}; use bitcoin::secp256k1::PublicKey; use bitcoin::Network; use chrono::Utc; @@ -86,13 +86,22 @@ pub(crate) fn read_network( NetworkGraph::new(network, logger) } -pub(crate) fn read_payment_info(path: &Path) -> PaymentInfoStorage { +pub(crate) fn read_inbound_payment_info(path: &Path) -> InboundPaymentInfoStorage { if let Ok(file) = File::open(path) { - if let Ok(info) = PaymentInfoStorage::read(&mut BufReader::new(file)) { + if let Ok(info) = InboundPaymentInfoStorage::read(&mut BufReader::new(file)) { return info; } } - PaymentInfoStorage { payments: HashMap::new() } + InboundPaymentInfoStorage { payments: HashMap::new() } +} + +pub(crate) fn read_outbound_payment_info(path: &Path) -> OutboundPaymentInfoStorage { + if let Ok(file) = File::open(path) { + if let Ok(info) = OutboundPaymentInfoStorage::read(&mut BufReader::new(file)) { + return info; + } + } + OutboundPaymentInfoStorage { payments: HashMap::new() } } pub(crate) fn read_scorer( diff --git a/src/main.rs b/src/main.rs index 33b1707..4c57c16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ use lightning::events::bump_transaction::{BumpTransactionEventHandler, Wallet}; use lightning::events::{Event, PaymentFailureReason, PaymentPurpose}; use lightning::ln::channelmanager::{self, RecentPaymentDetails}; use lightning::ln::channelmanager::{ - ChainParameters, ChannelManagerReadArgs, SimpleArcChannelManager, + ChainParameters, ChannelManagerReadArgs, PaymentId, SimpleArcChannelManager, }; use lightning::ln::msgs::DecodeError; use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler, SimpleArcPeerManager}; @@ -109,11 +109,19 @@ impl_writeable_tlv_based!(PaymentInfo, { (6, amt_msat, required), }); -pub(crate) struct PaymentInfoStorage { +pub(crate) struct InboundPaymentInfoStorage { payments: HashMap, } -impl_writeable_tlv_based!(PaymentInfoStorage, { +impl_writeable_tlv_based!(InboundPaymentInfoStorage, { + (0, payments, required), +}); + +pub(crate) struct OutboundPaymentInfoStorage { + payments: HashMap, +} + +impl_writeable_tlv_based!(OutboundPaymentInfoStorage, { (0, payments, required), }); @@ -139,7 +147,7 @@ pub(crate) type GossipVerifier = lightning_block_sync::gossip::GossipVerifier< Arc, SocketDescriptor, Arc, - Arc>, + Arc, IgnoringMessageHandler, Arc, >; @@ -158,7 +166,8 @@ pub(crate) type ChannelManager = pub(crate) type NetworkGraph = gossip::NetworkGraph>; -type OnionMessenger = SimpleArcOnionMessenger; +type OnionMessenger = + SimpleArcOnionMessenger; pub(crate) type BumpTxEventHandler = BumpTransactionEventHandler< Arc, @@ -170,8 +179,9 @@ pub(crate) type BumpTxEventHandler = BumpTransactionEventHandler< async fn handle_ldk_events( channel_manager: &Arc, bitcoind_client: &BitcoindClient, network_graph: &NetworkGraph, keys_manager: &KeysManager, - bump_tx_event_handler: &BumpTxEventHandler, inbound_payments: Arc>, - outbound_payments: Arc>, fs_store: &Arc, + bump_tx_event_handler: &BumpTxEventHandler, + inbound_payments: Arc>, + outbound_payments: Arc>, fs_store: &Arc, network: Network, event: Event, ) { match event { @@ -285,10 +295,12 @@ async fn handle_ldk_events( } fs_store.write("", "", INBOUND_PAYMENTS_FNAME, &inbound.encode()).unwrap(); } - Event::PaymentSent { payment_preimage, payment_hash, fee_paid_msat, .. } => { + Event::PaymentSent { + payment_preimage, payment_hash, fee_paid_msat, payment_id, .. + } => { let mut outbound = outbound_payments.lock().unwrap(); - for (hash, payment) in outbound.payments.iter_mut() { - if *hash == payment_hash { + for (id, payment) in outbound.payments.iter_mut() { + if *id == payment_id.unwrap() { payment.preimage = Some(payment_preimage); payment.status = HTLCStatus::Succeeded; println!( @@ -342,7 +354,7 @@ async fn handle_ldk_events( Event::PaymentPathFailed { .. } => {} Event::ProbeSuccessful { .. } => {} Event::ProbeFailed { .. } => {} - Event::PaymentFailed { payment_hash, reason, .. } => { + Event::PaymentFailed { payment_hash, reason, payment_id, .. } => { print!( "\nEVENT: Failed to send payment to payment hash {}: {:?}", payment_hash, @@ -352,8 +364,20 @@ async fn handle_ldk_events( io::stdout().flush().unwrap(); let mut outbound = outbound_payments.lock().unwrap(); - if outbound.payments.contains_key(&payment_hash) { - let payment = outbound.payments.get_mut(&payment_hash).unwrap(); + if outbound.payments.contains_key(&payment_id) { + let payment = outbound.payments.get_mut(&payment_id).unwrap(); + payment.status = HTLCStatus::Failed; + } + fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); + } + Event::InvoiceRequestFailed { payment_id } => { + print!("\nEVENT: Failed to request invoice to send payment with id {}", payment_id); + print!("> "); + io::stdout().flush().unwrap(); + + let mut outbound = outbound_payments.lock().unwrap(); + if outbound.payments.contains_key(&payment_id) { + let payment = outbound.payments.get_mut(&payment_id).unwrap(); payment.status = HTLCStatus::Failed; } fs_store.write("", "", OUTBOUND_PAYMENTS_FNAME, &outbound.encode()).unwrap(); @@ -754,7 +778,7 @@ async fn start_ldk() { Arc::clone(&keys_manager), Arc::clone(&logger), Arc::new(DefaultMessageRouter {}), - IgnoringMessageHandler {}, + Arc::clone(&channel_manager), IgnoringMessageHandler {}, )); let mut ephemeral_bytes = [0; 32]; @@ -825,32 +849,30 @@ async fn start_ldk() { } }); - let inbound_payments = Arc::new(Mutex::new(disk::read_payment_info(Path::new(&format!( - "{}/{}", - ldk_data_dir, INBOUND_PAYMENTS_FNAME - ))))); - let outbound_payments = Arc::new(Mutex::new(disk::read_payment_info(Path::new(&format!( - "{}/{}", - ldk_data_dir, OUTBOUND_PAYMENTS_FNAME - ))))); - let recent_payments_payment_hashes = channel_manager + let inbound_payments = Arc::new(Mutex::new(disk::read_inbound_payment_info(Path::new( + &format!("{}/{}", ldk_data_dir, INBOUND_PAYMENTS_FNAME), + )))); + let outbound_payments = Arc::new(Mutex::new(disk::read_outbound_payment_info(Path::new( + &format!("{}/{}", ldk_data_dir, OUTBOUND_PAYMENTS_FNAME), + )))); + let recent_payments_payment_ids = channel_manager .list_recent_payments() .into_iter() .filter_map(|p| match p { - RecentPaymentDetails::Pending { payment_hash, .. } => Some(payment_hash), - RecentPaymentDetails::Fulfilled { payment_hash, .. } => payment_hash, - RecentPaymentDetails::Abandoned { payment_hash, .. } => Some(payment_hash), - RecentPaymentDetails::AwaitingInvoice { payment_id: _ } => todo!(), + RecentPaymentDetails::Pending { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::Fulfilled { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::Abandoned { payment_id, .. } => Some(payment_id), + RecentPaymentDetails::AwaitingInvoice { payment_id } => Some(payment_id), }) - .collect::>(); - for (payment_hash, payment_info) in outbound_payments + .collect::>(); + for (payment_id, payment_info) in outbound_payments .lock() .unwrap() .payments .iter_mut() .filter(|(_, i)| matches!(i.status, HTLCStatus::Pending)) { - if !recent_payments_payment_hashes.contains(payment_hash) { + if !recent_payments_payment_ids.contains(payment_id) { payment_info.status = HTLCStatus::Failed; } } diff --git a/src/sweep.rs b/src/sweep.rs index 01cea9d..87577df 100644 --- a/src/sweep.rs +++ b/src/sweep.rs @@ -109,8 +109,8 @@ pub(crate) async fn periodic_sweep( } let destination_address = bitcoind_client.get_new_address().await; let output_descriptors = &outputs.iter().map(|a| a).collect::>(); - let tx_feerate = - bitcoind_client.get_est_sat_per_1000_weight(ConfirmationTarget::Background); + let tx_feerate = bitcoind_client + .get_est_sat_per_1000_weight(ConfirmationTarget::ChannelCloseMinimum); // We set nLockTime to the current height to discourage fee sniping. // Occasionally randomly pick a nLockTime even further back, so