X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=28101991cf700c35fab7e781e7389979564a0361;hb=bd16a1e409413ed0762d87c166819ad1fa62fa8b;hp=81312980a5a1550137078ab69506c894c6d35c69;hpb=baa727ea3867a823ff6fb51abae1d7da534628cb;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 81312980..28101991 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -12,11 +12,13 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1, self}; use crate::blinded_path::{BlindedHop, BlindedPath, Direction, IntroductionNode}; -use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs}; -use crate::ln::types::PaymentHash; -use crate::ln::channelmanager::{ChannelDetails, PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA}; +use crate::blinded_path::message; +use crate::blinded_path::payment::{ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs, self}; +use crate::ln::{PaymentHash, PaymentPreimage}; +use crate::ln::channelmanager::{ChannelDetails, PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA, RecipientOnionFields}; use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures}; use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; +use crate::ln::onion_utils; use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice}; use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath}; use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees}; @@ -121,7 +123,7 @@ impl> + Clone, L: Deref, ES: Deref, S: Deref, max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta, htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0), }; - Some(ForwardNode { + Some(payment::ForwardNode { tlvs: ForwardTlvs { short_channel_id, payment_relay, @@ -170,7 +172,7 @@ impl< G: Deref> + Clone, L: Deref, ES: Deref, S: Deref, fn create_blinded_paths< T: secp256k1::Signing + secp256k1::Verification > ( - &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { self.message_router.create_blinded_paths(recipient, peers, secp_ctx) } @@ -603,6 +605,17 @@ impl RouteParameters { pub fn from_payment_params_and_value(payment_params: PaymentParameters, final_value_msat: u64) -> Self { Self { payment_params, final_value_msat, max_total_routing_fee_msat: Some(final_value_msat / 100 + 50_000) } } + + /// Sets the maximum number of hops that can be included in a payment path, based on the provided + /// [`RecipientOnionFields`] and blinded paths. + pub fn set_max_path_length( + &mut self, recipient_onion: &RecipientOnionFields, is_keysend: bool, best_block_height: u32 + ) -> Result<(), ()> { + let keysend_preimage_opt = is_keysend.then(|| PaymentPreimage([42; 32])); + onion_utils::set_max_path_length( + self, recipient_onion, keysend_preimage_opt, best_block_height + ) + } } impl Writeable for RouteParameters { @@ -2001,12 +2014,29 @@ where L::Target: Logger { let max_total_routing_fee_msat = route_params.max_total_routing_fee_msat.unwrap_or(u64::max_value()); - log_trace!(logger, "Searching for a route from payer {} to {} {} MPP and {} first hops {}overriding the network graph with a fee limit of {} msat", + let first_hop_count = first_hops.map(|hops| hops.len()).unwrap_or(0); + log_trace!(logger, "Searching for a route from payer {} to {} {} MPP and {} first hops {}overriding the network graph of {} nodes and {} channels with a fee limit of {} msat", our_node_pubkey, LoggedPayeePubkey(payment_params.payee.node_id()), if allow_mpp { "with" } else { "without" }, - first_hops.map(|hops| hops.len()).unwrap_or(0), if first_hops.is_some() { "" } else { "not " }, + first_hop_count, if first_hops.is_some() { "" } else { "not " }, + network_graph.nodes().len(), network_graph.channels().len(), max_total_routing_fee_msat); + if first_hop_count < 10 { + if let Some(hops) = first_hops { + for hop in hops { + log_trace!( + logger, + " First hop through {}/{} can send between {}msat and {}msat (inclusive).", + hop.counterparty.node_id, + hop.get_outbound_payment_scid().unwrap_or(0), + hop.next_outbound_htlc_minimum_msat, + hop.next_outbound_htlc_limit_msat + ); + } + } + } + // Step (1). // Prepare the data we'll use for payee-to-payer search by // inserting first hops suggested by the caller as targets. @@ -2213,14 +2243,9 @@ where L::Target: Logger { // around again with a higher amount. if !contributes_sufficient_value { if should_log_candidate { - log_trace!(logger, "Ignoring {} due to insufficient value contribution.", LoggedCandidateHop(&$candidate)); - - if let Some(details) = first_hop_details { - log_trace!(logger, - "First hop candidate next_outbound_htlc_limit_msat: {}", - details.next_outbound_htlc_limit_msat, - ); - } + log_trace!(logger, "Ignoring {} due to insufficient value contribution (channel max {:?}).", + LoggedCandidateHop(&$candidate), + effective_capacity); } num_ignored_value_contribution += 1; } else if exceeds_max_path_length { @@ -2249,15 +2274,8 @@ where L::Target: Logger { } else if may_overpay_to_meet_path_minimum_msat { if should_log_candidate { log_trace!(logger, - "Ignoring {} to avoid overpaying to meet htlc_minimum_msat limit.", - LoggedCandidateHop(&$candidate)); - - if let Some(details) = first_hop_details { - log_trace!(logger, - "First hop candidate next_outbound_htlc_minimum_msat: {}", - details.next_outbound_htlc_minimum_msat, - ); - } + "Ignoring {} to avoid overpaying to meet htlc_minimum_msat limit ({}).", + LoggedCandidateHop(&$candidate), $candidate.htlc_minimum_msat()); } num_ignored_avoid_overpayment += 1; hit_minimum_limit = true; @@ -3315,8 +3333,9 @@ mod tests { #[cfg(c_bindings)] use crate::util::ser::Writer; + use bitcoin::amount::Amount; use bitcoin::hashes::Hash; - use bitcoin::network::constants::Network; + use bitcoin::network::Network; use bitcoin::blockdata::constants::ChainHash; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; @@ -4874,10 +4893,10 @@ mod tests { .push_slice(&PublicKey::from_secret_key(&secp_ctx, &privkeys[0]).serialize()) .push_slice(&PublicKey::from_secret_key(&secp_ctx, &privkeys[2]).serialize()) .push_opcode(opcodes::all::OP_PUSHNUM_2) - .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh(); + .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_p2wsh(); *chain_monitor.utxo_ret.lock().unwrap() = - UtxoResult::Sync(Ok(TxOut { value: 15, script_pubkey: good_script.clone() })); + UtxoResult::Sync(Ok(TxOut { value: Amount::from_sat(15), script_pubkey: good_script.clone() })); gossip_sync.add_utxo_lookup(Some(chain_monitor)); add_channel(&gossip_sync, &secp_ctx, &privkeys[0], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 333); @@ -5490,6 +5509,18 @@ mod tests { fee_proportional_millionths: 0, excess_data: Vec::new() }); + update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 5, + timestamp: 2, + flags: 3, // disable direction 1 + cltv_expiry_delta: 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: 200_000, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); // Path via {node7, node2, node4} is channels {12, 13, 6, 11}. // Add 100 sats to the capacities of {12, 13}, because these channels @@ -5667,6 +5698,18 @@ mod tests { fee_proportional_millionths: 0, excess_data: Vec::new() }); + update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 5, + timestamp: 2, + flags: 3, // disable direction 1 + cltv_expiry_delta: 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: 200_000, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); // Path via {node7, node2, node4} is channels {12, 13, 6, 11}. // Add 100 sats to the capacities of {12, 13}, because these channels @@ -5840,6 +5883,18 @@ mod tests { fee_proportional_millionths: 0, excess_data: Vec::new() }); + update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 5, + timestamp: 2, + flags: 3, // Disable direction 1 + cltv_expiry_delta: 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: 100_000, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); // Path via {node7, node2, node4} is channels {12, 13, 6, 11}. // All channels should be 100 sats capacity. But for the fee experiment, @@ -6232,92 +6287,104 @@ mod tests { let payment_params = PaymentParameters::from_node_id(nodes[6], 42); add_channel(&gossip_sync, &secp_ctx, &our_privkey, &privkeys[1], ChannelFeatures::from_le_bytes(id_to_feature_flags(6)), 6); - update_channel(&gossip_sync, &secp_ctx, &our_privkey, UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 6, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (6 << 4) | 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&our_privkey, 0), (&privkeys[1], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 6, + timestamp: 1, + flags, + cltv_expiry_delta: (6 << 4) | 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[1], NodeFeatures::from_le_bytes(id_to_feature_flags(1)), 0); add_channel(&gossip_sync, &secp_ctx, &privkeys[1], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(5)), 5); - update_channel(&gossip_sync, &secp_ctx, &privkeys[1], UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 5, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (5 << 4) | 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 100, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&privkeys[1], 0), (&privkeys[4], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 5, + timestamp: 1, + flags, + cltv_expiry_delta: (5 << 4) | 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 100, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[4], NodeFeatures::from_le_bytes(id_to_feature_flags(4)), 0); add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[3], ChannelFeatures::from_le_bytes(id_to_feature_flags(4)), 4); - update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 4, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (4 << 4) | 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&privkeys[4], 0), (&privkeys[3], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 4, + timestamp: 1, + flags, + cltv_expiry_delta: (4 << 4) | 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[3], NodeFeatures::from_le_bytes(id_to_feature_flags(3)), 0); add_channel(&gossip_sync, &secp_ctx, &privkeys[3], &privkeys[2], ChannelFeatures::from_le_bytes(id_to_feature_flags(3)), 3); - update_channel(&gossip_sync, &secp_ctx, &privkeys[3], UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 3, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (3 << 4) | 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&privkeys[3], 0), (&privkeys[2], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 3, + timestamp: 1, + flags, + cltv_expiry_delta: (3 << 4) | 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[2], NodeFeatures::from_le_bytes(id_to_feature_flags(2)), 0); add_channel(&gossip_sync, &secp_ctx, &privkeys[2], &privkeys[4], ChannelFeatures::from_le_bytes(id_to_feature_flags(2)), 2); - update_channel(&gossip_sync, &secp_ctx, &privkeys[2], UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 2, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (2 << 4) | 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&privkeys[2], 0), (&privkeys[4], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 2, + timestamp: 1, + flags, + cltv_expiry_delta: (2 << 4) | 0, + htlc_minimum_msat: 0, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_channel(&gossip_sync, &secp_ctx, &privkeys[4], &privkeys[6], ChannelFeatures::from_le_bytes(id_to_feature_flags(1)), 1); - update_channel(&gossip_sync, &secp_ctx, &privkeys[4], UnsignedChannelUpdate { - chain_hash: ChainHash::using_genesis_block(Network::Testnet), - short_channel_id: 1, - timestamp: 1, - flags: 0, - cltv_expiry_delta: (1 << 4) | 0, - htlc_minimum_msat: 100, - htlc_maximum_msat: MAX_VALUE_MSAT, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: Vec::new() - }); + for (key, flags) in [(&privkeys[4], 0), (&privkeys[6], 3)] { + update_channel(&gossip_sync, &secp_ctx, key, UnsignedChannelUpdate { + chain_hash: ChainHash::using_genesis_block(Network::Testnet), + short_channel_id: 1, + timestamp: 1, + flags, + cltv_expiry_delta: (1 << 4) | 0, + htlc_minimum_msat: 100, + htlc_maximum_msat: MAX_VALUE_MSAT, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: Vec::new() + }); + } add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[6], NodeFeatures::from_le_bytes(id_to_feature_flags(6)), 0); {