diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 0caee0801aa..a088f64f4d1 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -97,10 +97,6 @@ impl Router for FuzzRouter { action: msgs::ErrorAction::IgnoreError }) } - fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} - fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} } pub struct TestBroadcaster {} diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 57c665a2ef1..9b3b76c2b3a 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -140,10 +140,6 @@ impl Router for FuzzRouter { action: msgs::ErrorAction::IgnoreError }) } - fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} - fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} } struct TestBroadcaster { diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 83f72e46145..f6cc87fa72a 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -691,7 +691,7 @@ mod test { let first_hops = nodes[0].node.list_usable_channels(); let network_graph = &node_cfgs[0].network_graph; let logger = test_utils::TestLogger::new(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, &network_graph, @@ -1055,7 +1055,7 @@ mod test { let first_hops = nodes[0].node.list_usable_channels(); let network_graph = &node_cfgs[0].network_graph; let logger = test_utils::TestLogger::new(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &nodes[0].node.get_our_node_id(), ¶ms, &network_graph, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 6ab5149f4c5..234d072a8bd 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -2546,7 +2546,7 @@ where let best_block_height = self.best_block.read().unwrap().height(); self.pending_outbound_payments .send_payment(payment_hash, payment_secret, payment_id, retry_strategy, route_params, - &self.router, self.list_usable_channels(), self.compute_inflight_htlcs(), + &self.router, self.list_usable_channels(), || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, &self.logger, |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv| self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv)) @@ -2646,7 +2646,7 @@ where let best_block_height = self.best_block.read().unwrap().height(); self.pending_outbound_payments.send_spontaneous_payment(payment_preimage, payment_id, retry_strategy, route_params, &self.router, self.list_usable_channels(), - self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, + || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, &self.logger, |path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv| self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv)) @@ -7966,7 +7966,7 @@ mod tests { let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); let nodes = create_network(2, &node_cfgs, &node_chanmgrs); create_announced_chan_between_nodes(&nodes, 0, 1); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); // To start (1), send a regular payment but don't claim it. @@ -8074,7 +8074,7 @@ mod tests { }; let network_graph = nodes[0].network_graph.clone(); let first_hops = nodes[0].node.list_usable_channels(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::>()), @@ -8119,7 +8119,7 @@ mod tests { }; let network_graph = nodes[0].network_graph.clone(); let first_hops = nodes[0].node.list_usable_channels(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, &network_graph, Some(&first_hops.iter().collect::>()), @@ -8589,7 +8589,8 @@ pub mod bench { let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}; let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }; let logger_a = test_utils::TestLogger::with_id("node a".to_owned()); - let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(genesis_hash, &logger_a))); + let scorer = Mutex::new(test_utils::TestScorer::new()); + let router = test_utils::TestRouter::new(Arc::new(NetworkGraph::new(genesis_hash, &logger_a)), &scorer); let mut config: UserConfig = Default::default(); config.channel_handshake_config.minimum_depth = 1; @@ -8680,7 +8681,7 @@ pub mod bench { let usable_channels = $node_a.list_usable_channels(); let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id(), TEST_FINAL_CLTV) .with_features($node_b.invoice_features()); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let seed = [3u8; 32]; let keys_manager = KeysManager::new(&seed, 42, 42); let random_seed_bytes = keys_manager.get_secure_random_bytes(); diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs index 7bf51df5c7a..f7fadc1ecee 100644 --- a/lightning/src/ln/functional_test_utils.rs +++ b/lightning/src/ln/functional_test_utils.rs @@ -305,6 +305,7 @@ pub struct TestChanMonCfg { pub persister: test_utils::TestPersister, pub logger: test_utils::TestLogger, pub keys_manager: test_utils::TestKeysInterface, + pub scorer: Mutex, } pub struct NodeCfg<'a> { @@ -427,6 +428,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { channel_monitors.insert(monitor.get_funding_txo().0, monitor); } + let scorer = Mutex::new(test_utils::TestScorer::new()); let mut w = test_utils::TestVecWriter(Vec::new()); self.node.write(&mut w).unwrap(); <(BlockHash, ChannelManager<&test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestRouter, &test_utils::TestLogger>)>::read(&mut io::Cursor::new(w.0), ChannelManagerReadArgs { @@ -435,7 +437,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> { node_signer: self.keys_manager, signer_provider: self.keys_manager, fee_estimator: &test_utils::TestFeeEstimator { sat_per_kw: Mutex::new(253) }, - router: &test_utils::TestRouter::new(Arc::new(network_graph)), + router: &test_utils::TestRouter::new(Arc::new(network_graph), &scorer), chain_monitor: self.chain_monitor, tx_broadcaster: &broadcaster, logger: &self.logger, @@ -1570,7 +1572,7 @@ macro_rules! get_payment_preimage_hash { macro_rules! get_route { ($send_node: expr, $payment_params: expr, $recv_value: expr, $cltv: expr) => {{ use $crate::chain::keysinterface::EntropySource; - let scorer = $crate::util::test_utils::TestScorer::with_penalty(0); + let scorer = $crate::util::test_utils::TestScorer::new(); let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); $crate::routing::router::get_route( @@ -2124,7 +2126,7 @@ pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_rou let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id(), TEST_FINAL_CLTV) .with_features(expected_route.last().unwrap().node.invoice_features()); let network_graph = origin_node.network_graph.read_only(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let seed = [0u8; 32]; let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2289,8 +2291,9 @@ pub fn create_chanmon_cfgs(node_count: usize) -> Vec { let persister = test_utils::TestPersister::new(); let seed = [i as u8; 32]; let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet); + let scorer = Mutex::new(test_utils::TestScorer::new()); - chan_mon_cfgs.push(TestChanMonCfg { tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager }); + chan_mon_cfgs.push(TestChanMonCfg { tx_broadcaster, fee_estimator, chain_source, logger, persister, keys_manager, scorer }); } chan_mon_cfgs @@ -2308,7 +2311,7 @@ pub fn create_node_cfgs<'a>(node_count: usize, chanmon_cfgs: &'a Vec>()), diff --git a/lightning/src/ln/onion_route_tests.rs b/lightning/src/ln/onion_route_tests.rs index 1ed10a4a61d..fbc8e1c9e4e 100644 --- a/lightning/src/ln/onion_route_tests.rs +++ b/lightning/src/ln/onion_route_tests.rs @@ -928,7 +928,7 @@ macro_rules! get_phantom_route { htlc_maximum_msat: None, } ])]); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let network_graph = $nodes[0].network_graph.read_only(); (get_route( &$nodes[0].node.get_our_node_id(), &payment_params, &network_graph, diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index a9ced49f647..31ba9cb371f 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -402,22 +402,23 @@ impl OutboundPayments { } } - pub(super) fn send_payment( + pub(super) fn send_payment( &self, payment_hash: PaymentHash, payment_secret: &Option, payment_id: PaymentId, retry_strategy: Retry, route_params: RouteParameters, router: &R, - first_hops: Vec, inflight_htlcs: InFlightHtlcs, entropy_source: &ES, - node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: F, + first_hops: Vec, compute_inflight_htlcs: IH, entropy_source: &ES, + node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP, ) -> Result<(), PaymentSendFailure> where R::Target: Router, ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, - F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, + IH: Fn() -> InFlightHtlcs, + SP: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError>, { self.pay_internal(payment_id, Some((payment_hash, payment_secret, None, retry_strategy)), - route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, + route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } @@ -439,25 +440,26 @@ impl OutboundPayments { .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) } - pub(super) fn send_spontaneous_payment( + pub(super) fn send_spontaneous_payment( &self, payment_preimage: Option, payment_id: PaymentId, retry_strategy: Retry, route_params: RouteParameters, router: &R, - first_hops: Vec, inflight_htlcs: InFlightHtlcs, entropy_source: &ES, - node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: F + first_hops: Vec, inflight_htlcs: IH, entropy_source: &ES, + node_signer: &NS, best_block_height: u32, logger: &L, send_payment_along_path: SP ) -> Result where R::Target: Router, ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, - F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, + IH: Fn() -> InFlightHtlcs, + SP: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError>, { let preimage = payment_preimage .unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes())); let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner()); self.pay_internal(payment_id, Some((payment_hash, &None, Some(preimage), retry_strategy)), - route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, + route_params, router, first_hops, &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) .map(|()| payment_hash) .map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e }) @@ -525,26 +527,27 @@ impl OutboundPayments { } if let Some((payment_id, route_params)) = retry_id_route_params { core::mem::drop(outbounds); - if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), inflight_htlcs(), entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) { + if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, &send_payment_along_path) { log_info!(logger, "Errored retrying payment: {:?}", e); } } else { break } } } - fn pay_internal( + fn pay_internal( &self, payment_id: PaymentId, initial_send_info: Option<(PaymentHash, &Option, Option, Retry)>, route_params: RouteParameters, router: &R, first_hops: Vec, - inflight_htlcs: InFlightHtlcs, entropy_source: &ES, node_signer: &NS, best_block_height: u32, - logger: &L, send_payment_along_path: &F, + inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32, + logger: &L, send_payment_along_path: &SP, ) -> Result<(), PaymentSendFailure> where R::Target: Router, ES::Target: EntropySource, NS::Target: NodeSigner, L::Target: Logger, - F: Fn(&Vec, &Option, &PaymentHash, &Option, u64, + IH: Fn() -> InFlightHtlcs, + SP: Fn(&Vec, &Option, &PaymentHash, &Option, u64, u32, PaymentId, &Option, [u8; 32]) -> Result<(), APIError> { #[cfg(feature = "std")] { @@ -557,7 +560,7 @@ impl OutboundPayments { let route = router.find_route( &node_signer.get_node_id(Recipient::Node).unwrap(), &route_params, - Some(&first_hops.iter().collect::>()), &inflight_htlcs + Some(&first_hops.iter().collect::>()), &inflight_htlcs(), ).map_err(|e| PaymentSendFailure::ParameterError(APIError::APIMisuseError { err: format!("Failed to find a route for payment {}: {:?}", log_bytes!(payment_id.0), e), // TODO: add APIError::RouteNotFound }))?; @@ -1202,7 +1205,7 @@ mod tests { use crate::ln::outbound_payment::{OutboundPayments, Retry}; use crate::routing::gossip::NetworkGraph; use crate::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters}; - use crate::sync::Arc; + use crate::sync::{Arc, Mutex}; use crate::util::errors::APIError; use crate::util::test_utils; @@ -1218,7 +1221,8 @@ mod tests { let logger = test_utils::TestLogger::new(); let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger)); - let router = test_utils::TestRouter::new(network_graph); + let scorer = Mutex::new(test_utils::TestScorer::new()); + let router = test_utils::TestRouter::new(network_graph, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); @@ -1234,12 +1238,12 @@ mod tests { }; let err = if on_retry { outbound_payments.pay_internal( - PaymentId([0; 32]), None, expired_route_params, &&router, vec![], InFlightHtlcs::new(), + PaymentId([0; 32]), None, expired_route_params, &&router, vec![], &|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err() } else { outbound_payments.send_payment( PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), expired_route_params, - &&router, vec![], InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, + &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err() }; if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err { @@ -1257,7 +1261,8 @@ mod tests { let logger = test_utils::TestLogger::new(); let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); let network_graph = Arc::new(NetworkGraph::new(genesis_hash, &logger)); - let router = test_utils::TestRouter::new(network_graph); + let scorer = Mutex::new(test_utils::TestScorer::new()); + let router = test_utils::TestRouter::new(network_graph, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); @@ -1276,12 +1281,12 @@ mod tests { &Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()), &&keys_manager, 0).unwrap(); outbound_payments.pay_internal( - PaymentId([0; 32]), None, route_params, &&router, vec![], InFlightHtlcs::new(), + PaymentId([0; 32]), None, route_params, &&router, vec![], &|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &|_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err() } else { outbound_payments.send_payment( PaymentHash([0; 32]), &None, PaymentId([0; 32]), Retry::Attempts(0), route_params, - &&router, vec![], InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, + &&router, vec![], || InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, |_, _, _, _, _, _, _, _, _| Ok(())).unwrap_err() }; if let PaymentSendFailure::ParameterError(APIError::APIMisuseError { err }) = err { diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs index c6b170364d6..dbd78b6f8e6 100644 --- a/lightning/src/ln/payment_tests.rs +++ b/lightning/src/ln/payment_tests.rs @@ -21,8 +21,9 @@ use crate::ln::features::InvoiceFeatures; use crate::ln::msgs; use crate::ln::msgs::ChannelMessageHandler; use crate::ln::outbound_payment::Retry; -use crate::routing::gossip::RoutingFees; +use crate::routing::gossip::{EffectiveCapacity, RoutingFees}; use crate::routing::router::{get_route, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RouteParameters}; +use crate::routing::scoring::ChannelUsage; use crate::util::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider}; use crate::util::test_utils; use crate::util::errors::APIError; @@ -921,7 +922,7 @@ fn get_ldk_payment_preimage() { let payment_params = PaymentParameters::from_node_id(nodes[1].node.get_our_node_id(), TEST_FINAL_CLTV) .with_features(nodes[1].node.invoice_features()); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let route = get_route( @@ -1442,7 +1443,7 @@ fn do_test_intercepted_payment(test: InterceptTest) { let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(zero_conf_chan_config)]); let nodes = create_network(3, &node_cfgs, &node_chanmgrs); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let random_seed_bytes = chanmon_cfgs[0].keys_manager.get_secure_random_bytes(); let _ = create_announced_chan_between_nodes(&nodes, 0, 1).2; @@ -2175,6 +2176,16 @@ fn retry_multi_path_single_failed_payment() { final_value_msat: 100_000_001, final_cltv_expiry_delta: TEST_FINAL_CLTV }, Ok(route.clone())); + { + let scorer = chanmon_cfgs[0].scorer.lock().unwrap(); + // The initial send attempt, 2 paths + scorer.expect_usage(chans[0].short_channel_id.unwrap(), ChannelUsage { amount_msat: 10_000, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown }); + scorer.expect_usage(chans[1].short_channel_id.unwrap(), ChannelUsage { amount_msat: 100_000_001, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown }); + // The retry, 2 paths. Ensure that the in-flight HTLC amount is factored in. + scorer.expect_usage(chans[0].short_channel_id.unwrap(), ChannelUsage { amount_msat: 50_000_001, inflight_htlc_msat: 10_000, effective_capacity: EffectiveCapacity::Unknown }); + scorer.expect_usage(chans[1].short_channel_id.unwrap(), ChannelUsage { amount_msat: 50_000_000, inflight_htlc_msat: 0, effective_capacity: EffectiveCapacity::Unknown }); + } + nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap(); let htlc_msgs = nodes[0].node.get_and_clear_pending_msg_events(); assert_eq!(htlc_msgs.len(), 2); diff --git a/lightning/src/ln/shutdown_tests.rs b/lightning/src/ln/shutdown_tests.rs index c1fe23a62a6..5a5f054846f 100644 --- a/lightning/src/ln/shutdown_tests.rs +++ b/lightning/src/ln/shutdown_tests.rs @@ -76,7 +76,7 @@ fn updates_shutdown_wait() { let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1); let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); let logger = test_utils::TestLogger::new(); - let scorer = test_utils::TestScorer::with_penalty(0); + let scorer = test_utils::TestScorer::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs index a499532e6a9..6c2d70bd6f3 100644 --- a/lightning/src/routing/gossip.rs +++ b/lightning/src/routing/gossip.rs @@ -968,7 +968,7 @@ impl<'a> fmt::Debug for DirectedChannelInfo<'a> { /// /// While this may be smaller than the actual channel capacity, amounts greater than /// [`Self::as_msat`] should not be routed through the channel. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum EffectiveCapacity { /// The available liquidity in the channel known from being a channel counterparty, and thus a /// direct hop. diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 0e51b2bf86b..cfee77a67a2 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -72,22 +72,6 @@ impl>, L: Deref, S: Deref> Router for DefaultR &random_seed_bytes ) } - - fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64) { - self.scorer.lock().payment_path_failed(path, short_channel_id); - } - - fn notify_payment_path_successful(&self, path: &[&RouteHop]) { - self.scorer.lock().payment_path_successful(path); - } - - fn notify_payment_probe_successful(&self, path: &[&RouteHop]) { - self.scorer.lock().probe_successful(path); - } - - fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64) { - self.scorer.lock().probe_failed(path, short_channel_id); - } } /// A trait defining behavior for routing a payment. @@ -106,14 +90,6 @@ pub trait Router { ) -> Result { self.find_route(payer, route_params, first_hops, inflight_htlcs) } - /// Lets the router know that payment through a specific path has failed. - fn notify_payment_path_failed(&self, path: &[&RouteHop], short_channel_id: u64); - /// Lets the router know that payment through a specific path was successful. - fn notify_payment_path_successful(&self, path: &[&RouteHop]); - /// Lets the router know that a payment probe was successful. - fn notify_payment_probe_successful(&self, path: &[&RouteHop]); - /// Lets the router know that a payment probe failed. - fn notify_payment_probe_failed(&self, path: &[&RouteHop], short_channel_id: u64); } /// [`Score`] implementation that factors in in-flight HTLC liquidity. @@ -2116,7 +2092,7 @@ mod tests { use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE}; - use crate::routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; + use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel}; use crate::chain::transaction::OutPoint; use crate::chain::keysinterface::EntropySource; @@ -2186,7 +2162,7 @@ mod tests { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2219,7 +2195,7 @@ mod tests { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2241,7 +2217,7 @@ mod tests { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2369,7 +2345,7 @@ mod tests { let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); let config = UserConfig::default(); let payment_params = PaymentParameters::from_node_id(nodes[2], 42).with_features(channelmanager::provided_invoice_features(&config)); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2507,7 +2483,7 @@ mod tests { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2567,7 +2543,7 @@ mod tests { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2611,7 +2587,7 @@ mod tests { fn our_chans_test() { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2742,7 +2718,7 @@ mod tests { fn partial_route_hint_test() { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2843,7 +2819,7 @@ mod tests { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(empty_last_hop(&nodes)); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -2923,7 +2899,7 @@ mod tests { let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx); let last_hops = multi_hop_last_hops_hint([nodes[2], nodes[3]]); let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone()); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); // Test through channels 2, 3, 0xff00, 0xff01. @@ -2997,7 +2973,7 @@ mod tests { let last_hops = multi_hop_last_hops_hint([nodes[2], non_announced_pubkey]); let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone()); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); // Test through channels 2, 3, 0xff00, 0xff01. // Test shows that multiple hop hints are considered. @@ -3103,7 +3079,7 @@ mod tests { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_with_public_channel(&nodes)); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); // This test shows that public routes can be present in the invoice @@ -3154,7 +3130,7 @@ mod tests { fn our_chans_last_hop_connect_test() { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -3277,7 +3253,7 @@ mod tests { }]); let payment_params = PaymentParameters::from_node_id(target_node_id, 42).with_route_hints(vec![last_hops]); let our_chans = vec![get_channel_details(Some(42), middle_node_id, InitFeatures::from_le_bytes(vec![0b11]), outbound_capacity_msat)]; - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); @@ -3338,7 +3314,7 @@ mod tests { let (secp_ctx, network_graph, mut gossip_sync, chain_monitor, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -3614,7 +3590,7 @@ mod tests { // one of the latter hops is limited. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -3740,7 +3716,7 @@ mod tests { fn ignore_fee_first_hop_test() { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); @@ -3788,7 +3764,7 @@ mod tests { fn simple_mpp_route_test() { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -3948,7 +3924,7 @@ mod tests { fn long_mpp_route_test() { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4113,7 +4089,7 @@ mod tests { fn mpp_cheaper_route_test() { let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4283,7 +4259,7 @@ mod tests { // if the fee is not properly accounted for, the behavior is different. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4465,7 +4441,7 @@ mod tests { // This bug appeared in production in some specific channel configurations. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4557,7 +4533,7 @@ mod tests { // path finding we realize that we found more capacity than we need. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4719,7 +4695,7 @@ mod tests { let network = Arc::new(NetworkGraph::new(genesis_hash, Arc::clone(&logger))); let gossip_sync = P2PGossipSync::new(Arc::clone(&network), None, Arc::clone(&logger)); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let payment_params = PaymentParameters::from_node_id(nodes[6], 42); @@ -4850,7 +4826,7 @@ mod tests { // we calculated fees on a higher value, resulting in us ignoring such paths. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, _, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let payment_params = PaymentParameters::from_node_id(nodes[2], 42); @@ -4914,7 +4890,7 @@ mod tests { // resulting in us thinking there is no possible path, even if other paths exist. let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph(); let (our_privkey, our_id, privkeys, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let config = UserConfig::default(); @@ -4985,7 +4961,7 @@ mod tests { let genesis_hash = genesis_block(Network::Testnet).header.block_hash(); let logger = Arc::new(ln_test_utils::TestLogger::new()); let network_graph = NetworkGraph::new(genesis_hash, Arc::clone(&logger)); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let config = UserConfig::default(); let payment_params = PaymentParameters::from_node_id(nodes[0], 42).with_features(channelmanager::provided_invoice_features(&config)); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); @@ -5056,7 +5032,7 @@ mod tests { let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes)); // Without penalizing each hop 100 msats, a longer path with lower fees is chosen. - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let route = get_route( @@ -5071,7 +5047,7 @@ mod tests { // Applying a 100 msat penalty to each hop results in taking channels 7 and 10 to nodes[6] // from nodes[2] rather than channel 6, 11, and 8, even though the longer path is cheaper. - let scorer = ln_test_utils::TestScorer::with_penalty(100); + let scorer = FixedPenaltyScorer::with_penalty(100); let route = get_route( &our_id, &payment_params, &network_graph.read_only(), None, 100, 42, Arc::clone(&logger), &scorer, &random_seed_bytes @@ -5130,7 +5106,7 @@ mod tests { let network_graph = network.read_only(); // A path to nodes[6] exists when no penalties are applied to any channel. - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); let route = get_route( @@ -5245,7 +5221,7 @@ mod tests { let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let network_graph = network.read_only(); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); // Make sure that generally there is at least one route available let feasible_max_total_cltv_delta = 1008; @@ -5278,7 +5254,7 @@ mod tests { let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let network_graph = network.read_only(); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let mut payment_params = PaymentParameters::from_node_id(nodes[6], 0).with_route_hints(last_hops(&nodes)) .with_max_path_count(1); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); @@ -5305,7 +5281,7 @@ mod tests { let (_, our_id, _, nodes) = get_nodes(&secp_ctx); let network_graph = network.read_only(); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); @@ -5333,7 +5309,7 @@ mod tests { let (secp_ctx, network_graph, _, _, logger) = build_graph(); let (_, our_id, _, nodes) = get_nodes(&secp_ctx); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes)); let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet); @@ -5367,7 +5343,7 @@ mod tests { let network_graph = network.read_only(); let network_nodes = network_graph.nodes(); let network_channels = network_graph.channels(); - let scorer = ln_test_utils::TestScorer::with_penalty(0); + let scorer = ln_test_utils::TestScorer::new(); let payment_params = PaymentParameters::from_node_id(nodes[3], 0); let keys_manager = ln_test_utils::TestKeysInterface::new(&[4u8; 32], Network::Testnet); let random_seed_bytes = keys_manager.get_secure_random_bytes(); diff --git a/lightning/src/routing/scoring.rs b/lightning/src/routing/scoring.rs index f16dd2d5b40..7504e0840d2 100644 --- a/lightning/src/routing/scoring.rs +++ b/lightning/src/routing/scoring.rs @@ -260,7 +260,7 @@ impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> { } /// Proposed use of a channel passed as a parameter to [`Score::channel_penalty_msat`]. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct ChannelUsage { /// The amount to send through the channel, denominated in millisatoshis. pub amount_msat: u64, diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 83647a73385..1c2cfe00df0 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -22,10 +22,10 @@ use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use crate::ln::{msgs, wire}; use crate::ln::msgs::LightningError; use crate::ln::script::ShutdownScript; -use crate::routing::gossip::{NetworkGraph, NodeId}; +use crate::routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId}; use crate::routing::utxo::{UtxoLookup, UtxoLookupError, UtxoResult}; use crate::routing::router::{find_route, InFlightHtlcs, Route, RouteHop, RouteParameters, Router, ScorerAccountingForInFlightHtlcs}; -use crate::routing::scoring::FixedPenaltyScorer; +use crate::routing::scoring::{ChannelUsage, Score}; use crate::util::config::UserConfig; use crate::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use crate::util::events; @@ -48,6 +48,7 @@ use regex; use crate::io; use crate::prelude::*; +use core::cell::RefCell; use core::time::Duration; use crate::sync::{Mutex, Arc}; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -79,11 +80,12 @@ impl chaininterface::FeeEstimator for TestFeeEstimator { pub struct TestRouter<'a> { pub network_graph: Arc>, pub next_routes: Mutex)>>, + pub scorer: &'a Mutex, } impl<'a> TestRouter<'a> { - pub fn new(network_graph: Arc>) -> Self { - Self { network_graph, next_routes: Mutex::new(VecDeque::new()), } + pub fn new(network_graph: Arc>, scorer: &'a Mutex) -> Self { + Self { network_graph, next_routes: Mutex::new(VecDeque::new()), scorer } } pub fn expect_find_route(&self, query: RouteParameters, result: Result) { @@ -99,19 +101,40 @@ impl<'a> Router for TestRouter<'a> { ) -> Result { if let Some((find_route_query, find_route_res)) = self.next_routes.lock().unwrap().pop_front() { assert_eq!(find_route_query, *params); + if let Ok(ref route) = find_route_res { + let locked_scorer = self.scorer.lock().unwrap(); + let scorer = ScorerAccountingForInFlightHtlcs::new(locked_scorer, inflight_htlcs); + for path in &route.paths { + let mut aggregate_msat = 0u64; + for (idx, hop) in path.iter().rev().enumerate() { + aggregate_msat += hop.fee_msat; + let usage = ChannelUsage { + amount_msat: aggregate_msat, + inflight_htlc_msat: 0, + effective_capacity: EffectiveCapacity::Unknown, + }; + + // Since the path is reversed, the last element in our iteration is the first + // hop. + if idx == path.len() - 1 { + scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(payer), &NodeId::from_pubkey(&hop.pubkey), usage); + } else { + let curr_hop_path_idx = path.len() - 1 - idx; + scorer.channel_penalty_msat(hop.short_channel_id, &NodeId::from_pubkey(&path[curr_hop_path_idx - 1].pubkey), &NodeId::from_pubkey(&hop.pubkey), usage); + } + } + } + } return find_route_res; } let logger = TestLogger::new(); + let scorer = self.scorer.lock().unwrap(); find_route( payer, params, &self.network_graph, first_hops, &logger, - &ScorerAccountingForInFlightHtlcs::new(TestScorer::with_penalty(0), &inflight_htlcs), + &ScorerAccountingForInFlightHtlcs::new(scorer, &inflight_htlcs), &[42; 32] ) } - fn notify_payment_path_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} - fn notify_payment_path_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_successful(&self, _path: &[&RouteHop]) {} - fn notify_payment_probe_failed(&self, _path: &[&RouteHop], _short_channel_id: u64) {} } #[cfg(feature = "std")] // If we put this on the `if`, we get "attributes are not yet allowed on `if` expressions" on 1.41.1 @@ -889,5 +912,65 @@ impl Drop for TestChainSource { } } -/// A scorer useful in testing, when the passage of time isn't a concern. -pub type TestScorer = FixedPenaltyScorer; +pub struct TestScorer { + /// Stores a tuple of (scid, ChannelUsage) + scorer_expectations: RefCell>>, +} + +impl TestScorer { + pub fn new() -> Self { + Self { + scorer_expectations: RefCell::new(None), + } + } + + pub fn expect_usage(&self, scid: u64, expectation: ChannelUsage) { + self.scorer_expectations.borrow_mut().get_or_insert_with(|| VecDeque::new()).push_back((scid, expectation)); + } +} + +#[cfg(c_bindings)] +impl crate::util::ser::Writeable for TestScorer { + fn write(&self, _: &mut W) -> Result<(), crate::io::Error> { unreachable!(); } +} + +impl Score for TestScorer { + fn channel_penalty_msat( + &self, short_channel_id: u64, _source: &NodeId, _target: &NodeId, usage: ChannelUsage + ) -> u64 { + if let Some(scorer_expectations) = self.scorer_expectations.borrow_mut().as_mut() { + match scorer_expectations.pop_front() { + Some((scid, expectation)) => { + assert_eq!(expectation, usage); + assert_eq!(scid, short_channel_id); + }, + None => {}, + } + } + 0 + } + + fn payment_path_failed(&mut self, _actual_path: &[&RouteHop], _actual_short_channel_id: u64) {} + + fn payment_path_successful(&mut self, _actual_path: &[&RouteHop]) {} + + fn probe_failed(&mut self, _actual_path: &[&RouteHop], _: u64) {} + + fn probe_successful(&mut self, _actual_path: &[&RouteHop]) {} +} + +impl Drop for TestScorer { + fn drop(&mut self) { + #[cfg(feature = "std")] { + if std::thread::panicking() { + return; + } + } + + if let Some(scorer_expectations) = self.scorer_expectations.borrow().as_ref() { + if !scorer_expectations.is_empty() { + panic!("Unsatisfied scorer expectations: {:?}", scorer_expectations) + } + } + } +}