diff --git a/mutiny-core/Cargo.toml b/mutiny-core/Cargo.toml index b7faa0964..c8e1de8ea 100644 --- a/mutiny-core/Cargo.toml +++ b/mutiny-core/Cargo.toml @@ -26,9 +26,9 @@ serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } uuid = { version = "1.1.2", features = ["v4"] } esplora-client = { version = "0.5", default-features = false } -lightning = { version = "0.0.117", default-features = false, features = ["max_level_trace", "grind_signatures", "no-std"] } -lightning-invoice = { version = "0.25.0", default-features = false, features = ["no-std", "serde"] } -lightning-rapid-gossip-sync = { version = "0.0.117", default-features = false, features = ["no-std"] } +lightning = { version = "0.0.118", default-features = false, features = ["max_level_trace", "grind_signatures", "no-std"] } +lightning-invoice = { version = "0.26.0", default-features = false, features = ["no-std", "serde"] } +lightning-rapid-gossip-sync = { version = "0.0.118", default-features = false, features = ["no-std"] } chrono = "0.4.22" futures-util = { version = "0.3", default-features = false } reqwest = { version = "0.11", default-features = false, features = ["json"] } diff --git a/mutiny-core/src/event.rs b/mutiny-core/src/event.rs index 8e495cdc4..1f32adcbf 100644 --- a/mutiny-core/src/event.rs +++ b/mutiny-core/src/event.rs @@ -17,10 +17,7 @@ use core::fmt; use lightning::events::{Event, PaymentPurpose}; use lightning::sign::SpendableOutputDescriptor; use lightning::{ - chain::chaininterface::{ConfirmationTarget, FeeEstimator}, - log_debug, log_error, log_info, log_warn, - util::errors::APIError, - util::logger::Logger, + log_debug, log_error, log_info, log_warn, util::errors::APIError, util::logger::Logger, }; use lightning_invoice::Bolt11Invoice; use serde::{Deserialize, Serialize}; @@ -571,6 +568,10 @@ impl EventHandler { } Event::HTLCIntercepted { .. } => {} Event::BumpTransaction(event) => self.bump_tx_event_handler.handle_event(&event), + Event::InvoiceRequestFailed { payment_id } => { + // we don't support bolt 12 yet + log_warn!(self.logger, "EVENT: InvoiceRequestFailed: {payment_id}"); + } } } @@ -604,9 +605,7 @@ impl EventHandler { output_descriptors.len() ); - let tx_feerate = self - .fee_estimator - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let tx_feerate = self.fee_estimator.get_normal_fee_rate(); // We set nLockTime to the current height to discourage fee sniping. // Occasionally randomly pick a nLockTime even further back, so diff --git a/mutiny-core/src/fees.rs b/mutiny-core/src/fees.rs index d08deb2f6..5178b4f20 100644 --- a/mutiny-core/src/fees.rs +++ b/mutiny-core/src/fees.rs @@ -53,8 +53,7 @@ impl MutinyFeeEstimator { sats_per_kw: Option, ) -> u64 { // if no fee rate is provided, use the normal confirmation target - let sats_per_kw = sats_per_kw - .unwrap_or_else(|| self.get_est_sat_per_1000_weight(ConfirmationTarget::Normal)); + let sats_per_kw = sats_per_kw.unwrap_or_else(|| self.get_normal_fee_rate()); let expected_weight = { // Calculate the non-witness and witness data sizes let non_witness_size = TX_OVERHEAD @@ -144,6 +143,21 @@ impl MutinyFeeEstimator { Ok(()) } + + pub fn get_low_fee_rate(&self) -> u32 { + // MinAllowedNonAnchorChannelRemoteFee is a fee rate we expect to get slowly + self.get_est_sat_per_1000_weight(ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee) + } + + pub fn get_normal_fee_rate(&self) -> u32 { + // NonAnchorChannelFee is a fee rate we expect to be confirmed in 6 blocks + self.get_est_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee) + } + + pub fn get_high_fee_rate(&self) -> u32 { + // OnChainSweep is the highest fee rate we have, so use that + self.get_est_sat_per_1000_weight(ConfirmationTarget::OnChainSweep) + } } impl FeeEstimator for MutinyFeeEstimator { @@ -151,7 +165,7 @@ impl FeeEstimator for MutinyFeeEstimator { let num_blocks = num_blocks_from_conf_target(confirmation_target); let fallback_fee = fallback_fee_from_conf_target(confirmation_target); - match self.storage.get_fee_estimates() { + let fee = match self.storage.get_fee_estimates() { Err(_) | Ok(None) => fallback_fee, Ok(Some(estimates)) => { let found = estimates.get(&num_blocks.to_string()); @@ -160,13 +174,7 @@ impl FeeEstimator for MutinyFeeEstimator { log_trace!(self.logger, "Got fee rate from saved cache!"); let sats_vbyte = num.to_owned(); // convert to sats per kw - let mut fee_rate = sats_vbyte * 250.0; - - // if we're using the high priority target, multiply by 3 - // this should help prevent force closures from fee disputes - if confirmation_target == ConfirmationTarget::HighPriority { - fee_rate *= 3.0; - } + let fee_rate = sats_vbyte * 250.0; // return the fee rate, but make sure it's not lower than the floor (fee_rate as u32).max(FEERATE_FLOOR_SATS_PER_KW) @@ -174,29 +182,38 @@ impl FeeEstimator for MutinyFeeEstimator { None => fallback_fee, } } + }; + + // any post processing we do after the we get the fee rate from the cache + match confirmation_target { + ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => fee * 30, // multiply by 30 to help prevent force closes + ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => fee - 250, // helps with rounding errors + _ => fee, } } } fn num_blocks_from_conf_target(confirmation_target: ConfirmationTarget) -> usize { match confirmation_target { - // MempoolMinimum is only used for anchor channels, we just set the target to 1008 - // as that is esplora's highest block target available - ConfirmationTarget::MempoolMinimum => 1008, - // Background is VERY lax and may never confirm if used directly - // it is only meant for lower ranges of transaction to enter mempool - ConfirmationTarget::Background => 1008, - ConfirmationTarget::Normal => 6, - ConfirmationTarget::HighPriority => 1, + ConfirmationTarget::AnchorChannelFee => 1008, + ConfirmationTarget::MinAllowedAnchorChannelRemoteFee => 1008, + ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => 1008, + ConfirmationTarget::ChannelCloseMinimum => 1008, + ConfirmationTarget::NonAnchorChannelFee => 6, + ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => 1, + ConfirmationTarget::OnChainSweep => 1, } } fn fallback_fee_from_conf_target(confirmation_target: ConfirmationTarget) -> u32 { match confirmation_target { - ConfirmationTarget::MempoolMinimum => 3 * 250, - ConfirmationTarget::Background => 10 * 250, - ConfirmationTarget::Normal => 20 * 250, - ConfirmationTarget::HighPriority => 50 * 250, + ConfirmationTarget::MinAllowedAnchorChannelRemoteFee => 3 * 250, + ConfirmationTarget::MinAllowedNonAnchorChannelRemoteFee => 3 * 250, + ConfirmationTarget::ChannelCloseMinimum => 10 * 250, + ConfirmationTarget::AnchorChannelFee => 10 * 250, + ConfirmationTarget::NonAnchorChannelFee => 20 * 250, + ConfirmationTarget::MaxAllowedNonAnchorChannelRemoteFee => 50 * 250, + ConfirmationTarget::OnChainSweep => 50 * 250, } } @@ -229,12 +246,15 @@ mod test { #[test] fn test_num_blocks_from_conf_target() { assert_eq!( - num_blocks_from_conf_target(ConfirmationTarget::Background), + num_blocks_from_conf_target(ConfirmationTarget::ChannelCloseMinimum), 1008 ); - assert_eq!(num_blocks_from_conf_target(ConfirmationTarget::Normal), 6); assert_eq!( - num_blocks_from_conf_target(ConfirmationTarget::HighPriority), + num_blocks_from_conf_target(ConfirmationTarget::NonAnchorChannelFee), + 6 + ); + assert_eq!( + num_blocks_from_conf_target(ConfirmationTarget::OnChainSweep), 1 ); } @@ -242,15 +262,15 @@ mod test { #[test] fn test_fallback_fee_from_conf_target() { assert_eq!( - fallback_fee_from_conf_target(ConfirmationTarget::Background), + fallback_fee_from_conf_target(ConfirmationTarget::ChannelCloseMinimum), 2_500 ); assert_eq!( - fallback_fee_from_conf_target(ConfirmationTarget::Normal), + fallback_fee_from_conf_target(ConfirmationTarget::NonAnchorChannelFee), 5_000 ); assert_eq!( - fallback_fee_from_conf_target(ConfirmationTarget::HighPriority), + fallback_fee_from_conf_target(ConfirmationTarget::OnChainSweep), 12_500 ); } @@ -288,17 +308,17 @@ mod test { // test that we get the fee rate from the cache assert_eq!( - fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Normal), + fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::NonAnchorChannelFee), 2500 ); // test that we get the fallback fee rate assert_eq!( - fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::Background), + fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::ChannelCloseMinimum), 2_500 ); assert_eq!( - fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority), + fee_estimator.get_est_sat_per_1000_weight(ConfirmationTarget::OnChainSweep), 12_500 ); } diff --git a/mutiny-core/src/node.rs b/mutiny-core/src/node.rs index a6e871080..ca531e117 100644 --- a/mutiny-core/src/node.rs +++ b/mutiny-core/src/node.rs @@ -32,7 +32,6 @@ use core::time::Duration; use lightning::chain::channelmonitor::ChannelMonitor; use lightning::util::ser::{ReadableArgs, Writeable}; use lightning::{ - chain::chaininterface::{ConfirmationTarget, FeeEstimator}, ln::channelmanager::{RecipientOnionFields, RetryableSendFailure}, routing::scoring::ProbabilisticScoringFeeParameters, util::config::ChannelConfig, @@ -1409,10 +1408,7 @@ impl Node { let sats_per_vbyte = if let Some(sats_vbyte) = fee_rate { sats_vbyte } else { - let sats_per_kw = self - .wallet - .fees - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let sats_per_kw = self.wallet.fees.get_normal_fee_rate(); FeeRate::from_sat_per_kwu(sats_per_kw as f32).as_sat_per_vb() }; @@ -1483,10 +1479,8 @@ impl Node { total }; - let sats_per_kw = self - .wallet - .fees - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let sats_per_kw = self.wallet.fees.get_normal_fee_rate(); + // Calculate the expected transaction fee let expected_fee = self.wallet.fees.calculate_expected_fee( utxos.len(), diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index ee7fc10c1..56f209f96 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -41,7 +41,6 @@ use bitcoin::{Address, Network, OutPoint, Transaction, Txid}; use core::time::Duration; use esplora_client::Builder; use futures::{future::join_all, lock::Mutex}; -use lightning::chain::chaininterface::{ConfirmationTarget, FeeEstimator}; use lightning::chain::Confirm; use lightning::events::ClosureReason; use lightning::io::Read; @@ -1460,25 +1459,19 @@ impl NodeManager { /// Gets a fee estimate for a very low priority transaction. /// Value is in sat/vbyte. pub fn estimate_fee_low(&self) -> u32 { - self.fee_estimator - .get_est_sat_per_1000_weight(ConfirmationTarget::Background) - / 250 + self.fee_estimator.get_low_fee_rate() / 250 } /// Gets a fee estimate for an average priority transaction. /// Value is in sat/vbyte. pub fn estimate_fee_normal(&self) -> u32 { - self.fee_estimator - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal) - / 250 + self.fee_estimator.get_normal_fee_rate() / 250 } /// Gets a fee estimate for an high priority transaction. /// Value is in sat/vbyte. pub fn estimate_fee_high(&self) -> u32 { - self.fee_estimator - .get_est_sat_per_1000_weight(ConfirmationTarget::HighPriority) - / 250 + self.fee_estimator.get_high_fee_rate() / 250 } /// Creates a new lightning node and adds it to the manager. @@ -2077,9 +2070,7 @@ impl NodeManager { // ldk uses background fee rate for closing channels which can be very slow // so we use normal fee rate instead - let fee_rate = self - .fee_estimator - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let fee_rate = self.wallet.fees.get_normal_fee_rate(); node.channel_manager .close_channel_with_feerate_and_script( diff --git a/mutiny-core/src/onchain.rs b/mutiny-core/src/onchain.rs index 974ff5b98..75e5a7df3 100644 --- a/mutiny-core/src/onchain.rs +++ b/mutiny-core/src/onchain.rs @@ -15,7 +15,6 @@ use bitcoin::hashes::hex::ToHex; use bitcoin::psbt::PartiallySignedTransaction; use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey}; use bitcoin::{Address, Network, OutPoint, Script, Transaction, Txid}; -use lightning::chain::chaininterface::{ConfirmationTarget, FeeEstimator}; use lightning::events::bump_transaction::{Utxo, WalletSource}; use lightning::util::logger::Logger; use lightning::{log_debug, log_error, log_info, log_warn}; @@ -447,9 +446,7 @@ impl OnChainWallet { let fee_rate = if let Some(rate) = fee_rate { FeeRate::from_sat_per_vb(rate) } else { - let sat_per_kwu = self - .fees - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let sat_per_kwu = self.fees.get_normal_fee_rate(); FeeRate::from_sat_per_kwu(sat_per_kwu as f32) }; let (mut psbt, details) = { @@ -495,9 +492,7 @@ impl OnChainWallet { let fee_rate = if let Some(rate) = fee_rate { FeeRate::from_sat_per_vb(rate) } else { - let sat_per_kwu = self - .fees - .get_est_sat_per_1000_weight(ConfirmationTarget::Normal); + let sat_per_kwu = self.fees.get_normal_fee_rate(); FeeRate::from_sat_per_kwu(sat_per_kwu as f32) }; let (mut psbt, details) = { diff --git a/mutiny-core/src/peermanager.rs b/mutiny-core/src/peermanager.rs index b14a69b0f..aab2db886 100644 --- a/mutiny-core/src/peermanager.rs +++ b/mutiny-core/src/peermanager.rs @@ -13,7 +13,6 @@ use std::{net::SocketAddr, sync::atomic::AtomicBool}; use crate::networking::socket::{schedule_descriptor_read, MutinySocketDescriptor}; use crate::scb::message_handler::SCBMessageHandler; -use bitcoin::BlockHash; use lightning::events::{MessageSendEvent, MessageSendEventsProvider}; use lightning::ln::features::{InitFeatures, NodeFeatures}; use lightning::ln::msgs; @@ -22,7 +21,6 @@ use lightning::ln::peer_handler::PeerHandleError; use lightning::ln::peer_handler::{IgnoringMessageHandler, PeerManager as LdkPeerManager}; use lightning::log_warn; use lightning::routing::gossip::NodeId; -use lightning::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult}; use lightning::util::logger::Logger; use std::sync::Arc; @@ -179,16 +177,6 @@ impl MessageSendEventsProvider for GossipMessageHandler { } } -// I needed some type to implement RoutingMessageHandler, but I don't want to implement it -// we don't need to lookup UTXOs, so we can just return an error -// This should never actually be called because we are passing in None for the UTXO lookup -struct ErroringUtxoLookup {} -impl UtxoLookup for ErroringUtxoLookup { - fn get_utxo(&self, _genesis_hash: &BlockHash, _short_channel_id: u64) -> UtxoResult { - UtxoResult::Sync(Err(UtxoLookupError::UnknownTx)) - } -} - impl RoutingMessageHandler for GossipMessageHandler { fn handle_node_announcement( &self, diff --git a/mutiny-wasm/Cargo.toml b/mutiny-wasm/Cargo.toml index 22848718d..e7cf23d49 100644 --- a/mutiny-wasm/Cargo.toml +++ b/mutiny-wasm/Cargo.toml @@ -24,8 +24,8 @@ wasm-bindgen-futures = "0.4.33" serde = { version = "^1.0", features = ["derive"] } serde_json = { version = "^1.0" } bitcoin = { version = "0.29.2", default-features = false, features = ["serde", "secp-recovery", "rand"] } -lightning = { version = "0.0.117", default-features = false, features = ["no-std"] } -lightning-invoice = { version = "0.25.0", default-features = false, features = ["no-std"] } +lightning = { version = "0.0.118", default-features = false, features = ["no-std"] } +lightning-invoice = { version = "0.26.0", default-features = false, features = ["no-std"] } thiserror = "1.0" instant = { version = "0.1", features = ["wasm-bindgen"] } lnurl-rs = { version = "0.2.6", default-features = false }