]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Merge pull request #2966 from G8XSU/2647-distribute
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Thu, 20 Jun 2024 16:51:54 +0000 (09:51 -0700)
committerGitHub <noreply@github.com>
Thu, 20 Jun 2024 16:51:54 +0000 (09:51 -0700)
Optimize ChannelMonitor persistence on block connections.

22 files changed:
fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
lightning-rapid-gossip-sync/src/lib.rs
lightning-rapid-gossip-sync/src/processing.rs
lightning/src/blinded_path/message.rs
lightning/src/blinded_path/payment.rs
lightning/src/chain/channelmonitor.rs
lightning/src/events/mod.rs
lightning/src/ln/async_signer_tests.rs
lightning/src/ln/chanmon_update_fail_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/offers_tests.rs
lightning/src/ln/outbound_payment.rs
lightning/src/ln/payment_tests.rs
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/routing/router.rs
lightning/src/util/test_channel_signer.rs
lightning/src/util/test_utils.rs
rustfmt_excluded_files

index c4d179e745cd6ed125f99fa578f501e78c47bc7c..423e69eb8f6f39ed94e61c8a565d366569724b2e 100644 (file)
@@ -396,12 +396,7 @@ impl SignerProvider for KeyProvider {
                let inner: InMemorySigner = ReadableArgs::read(&mut reader, self)?;
                let state = self.make_enforcement_state_cell(inner.commitment_seed);
 
-               Ok(TestChannelSigner {
-                       inner,
-                       state,
-                       disable_revocation_policy_check: false,
-                       available: Arc::new(Mutex::new(true)),
-               })
+               Ok(TestChannelSigner::new_with_revoked(inner, state, false))
        }
 
        fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result<ScriptBuf, ()> {
index 2807b6dd4195e6f14d9e434f8b8268199ae5c876..a2ae07a2149045e14742174f7df16f2888cfed61 100644 (file)
@@ -1366,8 +1366,8 @@ mod tests {
 
                // process the now-pending HTLC forward
                ext_from_hex("07", &mut test);
-               // Two feerate requests to check dust exposure
-               ext_from_hex("00fd00fd", &mut test);
+               // Three feerate requests to check dust exposure
+               ext_from_hex("00fd00fd00fd", &mut test);
                // client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: UpdateHTLCs event for node 03020000 with 1 HTLCs for channel 3f000000)
 
                // we respond with commitment_signed then revoke_and_ack (a weird, but valid, order)
@@ -1478,8 +1478,8 @@ mod tests {
                // process the now-pending HTLC forward
                ext_from_hex("07", &mut test);
 
-               // Two feerate requests to check dust exposure
-               ext_from_hex("00fd00fd", &mut test);
+               // Three feerate requests to check dust exposure
+               ext_from_hex("00fd00fd00fd", &mut test);
 
                // client now sends id 1 update_add_htlc and commitment_signed (CHECK 7 duplicate)
                // we respond with revoke_and_ack, then commitment_signed, then update_fail_htlc
@@ -1602,8 +1602,8 @@ mod tests {
 
                // process the now-pending HTLC forward
                ext_from_hex("07", &mut test);
-               // Two feerate requests to check dust exposure
-               ext_from_hex("00fd00fd", &mut test);
+               // Three feerate requests to check dust exposure
+               ext_from_hex("00fd00fd00fd", &mut test);
                // client now sends id 1 update_add_htlc and commitment_signed (CHECK 7 duplicate)
 
                // connect a block with one transaction of len 125
index ecc52553038ed763fd228851f5816e91327b6087..c6951301cd774d701aa476f4612b5209e80b54ef 100644 (file)
@@ -1,6 +1,5 @@
 #![deny(rustdoc::broken_intra_doc_links)]
 #![deny(rustdoc::private_intra_doc_links)]
-
 #![deny(missing_docs)]
 #![deny(unsafe_code)]
 #![deny(non_upper_case_globals)]
 
 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
 
-#[cfg(ldk_bench)] extern crate criterion;
+#[cfg(ldk_bench)]
+extern crate criterion;
 
 #[cfg(not(feature = "std"))]
 extern crate alloc;
 
-#[cfg(feature = "std")]
-use std::fs::File;
 use core::ops::Deref;
 use core::sync::atomic::{AtomicBool, Ordering};
+#[cfg(feature = "std")]
+use std::fs::File;
 
 use lightning::io;
 use lightning::ln::msgs::{DecodeError, LightningError};
@@ -121,21 +121,22 @@ impl From<LightningError> for GraphSyncError {
 /// See [crate-level documentation] for usage.
 ///
 /// [crate-level documentation]: crate
-pub struct RapidGossipSync<NG: Deref<Target=NetworkGraph<L>>, L: Deref>
-where L::Target: Logger {
+pub struct RapidGossipSync<NG: Deref<Target = NetworkGraph<L>>, L: Deref>
+where
+       L::Target: Logger,
+{
        network_graph: NG,
        logger: L,
-       is_initial_sync_complete: AtomicBool
+       is_initial_sync_complete: AtomicBool,
 }
 
-impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
+impl<NG: Deref<Target = NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L>
+where
+       L::Target: Logger,
+{
        /// Instantiate a new [`RapidGossipSync`] instance.
        pub fn new(network_graph: NG, logger: L) -> Self {
-               Self {
-                       network_graph,
-                       logger,
-                       is_initial_sync_complete: AtomicBool::new(false)
-               }
+               Self { network_graph, logger, is_initial_sync_complete: AtomicBool::new(false) }
        }
 
        /// Sync gossip data from a file.
@@ -147,8 +148,7 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
        ///
        #[cfg(feature = "std")]
        pub fn sync_network_graph_with_file_path(
-               &self,
-               sync_path: &str,
+               &self, sync_path: &str,
        ) -> Result<u32, GraphSyncError> {
                let mut file = File::open(sync_path)?;
                self.update_network_graph_from_byte_stream(&mut file)
@@ -169,7 +169,9 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
        ///
        /// `update_data`: `&[u8]` binary stream that comprises the update data
        /// `current_time_unix`: `Option<u64>` optional current timestamp to verify data age
-       pub fn update_network_graph_no_std(&self, update_data: &[u8], current_time_unix: Option<u64>) -> Result<u32, GraphSyncError> {
+       pub fn update_network_graph_no_std(
+               &self, update_data: &[u8], current_time_unix: Option<u64>,
+       ) -> Result<u32, GraphSyncError> {
                let mut read_cursor = io::Cursor::new(update_data);
                self.update_network_graph_from_byte_stream_no_std(&mut read_cursor, current_time_unix)
        }
@@ -195,10 +197,10 @@ mod tests {
 
        use bitcoin::Network;
 
+       use crate::{GraphSyncError, RapidGossipSync};
        use lightning::ln::msgs::DecodeError;
        use lightning::routing::gossip::NetworkGraph;
        use lightning::util::test_utils::TestLogger;
-       use crate::{GraphSyncError, RapidGossipSync};
 
        #[test]
        fn test_sync_from_file() {
@@ -294,8 +296,7 @@ mod tests {
 
                let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
                let start = std::time::Instant::now();
-               let sync_result = rapid_sync
-                       .sync_network_graph_with_file_path("./res/full_graph.lngossip");
+               let sync_result = rapid_sync.sync_network_graph_with_file_path("./res/full_graph.lngossip");
                if let Err(GraphSyncError::DecodeError(DecodeError::Io(io_error))) = &sync_result {
                        let error_string = format!("Input file lightning-rapid-gossip-sync/res/full_graph.lngossip is missing! Download it from https://bitcoin.ninja/ldk-compressed_graph-285cb27df79-2022-07-21.bin\n\n{:?}", io_error);
                        #[cfg(not(require_route_graph_test))]
index b996cfaca29203f73fb0bd638b101e67d0fe353f..c7b8a8321724a926c85b42aa9da15de49981a496 100644 (file)
@@ -5,12 +5,15 @@ use core::sync::atomic::Ordering;
 use bitcoin::blockdata::constants::ChainHash;
 use bitcoin::secp256k1::PublicKey;
 
-use lightning::ln::msgs::{DecodeError, ErrorAction, LightningError, SocketAddress, UnsignedChannelUpdate, UnsignedNodeAnnouncement};
+use lightning::io;
+use lightning::ln::msgs::{
+       DecodeError, ErrorAction, LightningError, SocketAddress, UnsignedChannelUpdate,
+       UnsignedNodeAnnouncement,
+};
 use lightning::routing::gossip::{NetworkGraph, NodeAlias, NodeId};
 use lightning::util::logger::Logger;
-use lightning::{log_debug, log_warn, log_trace, log_given_level, log_gossip};
 use lightning::util::ser::{BigSize, FixedLengthReader, Readable};
-use lightning::io;
+use lightning::{log_debug, log_given_level, log_gossip, log_trace, log_warn};
 
 use crate::{GraphSyncError, RapidGossipSync};
 
@@ -18,7 +21,7 @@ use crate::{GraphSyncError, RapidGossipSync};
 use std::time::{SystemTime, UNIX_EPOCH};
 
 #[cfg(all(not(feature = "std"), not(test)))]
-use alloc::{vec::Vec, borrow::ToOwned};
+use alloc::{borrow::ToOwned, vec::Vec};
 use lightning::ln::features::NodeFeatures;
 
 /// The purpose of this prefix is to identify the serialization format, should other rapid gossip
@@ -35,11 +38,13 @@ const MAX_INITIAL_NODE_ID_VECTOR_CAPACITY: u32 = 50_000;
 /// suggestion.
 const STALE_RGS_UPDATE_AGE_LIMIT_SECS: u64 = 60 * 60 * 24 * 14;
 
-impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L::Target: Logger {
+impl<NG: Deref<Target = NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L>
+where
+       L::Target: Logger,
+{
        #[cfg(feature = "std")]
        pub(crate) fn update_network_graph_from_byte_stream<R: io::Read>(
-               &self,
-               read_cursor: &mut R,
+               &self, read_cursor: &mut R,
        ) -> Result<u32, GraphSyncError> {
                #[allow(unused_mut, unused_assignments)]
                let mut current_time_unix = None;
@@ -47,15 +52,18 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                {
                        // Note that many tests rely on being able to set arbitrarily old timestamps, thus we
                        // disable this check during tests!
-                       current_time_unix = Some(SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs());
+                       current_time_unix = Some(
+                               SystemTime::now()
+                                       .duration_since(UNIX_EPOCH)
+                                       .expect("Time must be > 1970")
+                                       .as_secs(),
+                       );
                }
                self.update_network_graph_from_byte_stream_no_std(read_cursor, current_time_unix)
        }
 
        pub(crate) fn update_network_graph_from_byte_stream_no_std<R: io::Read>(
-               &self,
-               mut read_cursor: &mut R,
-               current_time_unix: Option<u64>
+               &self, mut read_cursor: &mut R, current_time_unix: Option<u64>,
        ) -> Result<u32, GraphSyncError> {
                log_trace!(self.logger, "Processing RGS data...");
                let mut protocol_prefix = [0u8; 3];
@@ -75,19 +83,24 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                let chain_hash: ChainHash = Readable::read(read_cursor)?;
                let ng_chain_hash = self.network_graph.get_chain_hash();
                if chain_hash != ng_chain_hash {
-                       return Err(
-                               LightningError {
-                                       err: "Rapid Gossip Sync data's chain hash does not match the network graph's".to_owned(),
-                                       action: ErrorAction::IgnoreError,
-                               }.into()
-                       );
+                       return Err(LightningError {
+                               err: "Rapid Gossip Sync data's chain hash does not match the network graph's"
+                                       .to_owned(),
+                               action: ErrorAction::IgnoreError,
+                       }
+                       .into());
                }
 
                let latest_seen_timestamp: u32 = Readable::read(read_cursor)?;
 
                if let Some(time) = current_time_unix {
-                       if (latest_seen_timestamp as u64) < time.saturating_sub(STALE_RGS_UPDATE_AGE_LIMIT_SECS) {
-                               return Err(LightningError{err: "Rapid Gossip Sync data is more than two weeks old".to_owned(), action: ErrorAction::IgnoreError}.into());
+                       if (latest_seen_timestamp as u64) < time.saturating_sub(STALE_RGS_UPDATE_AGE_LIMIT_SECS)
+                       {
+                               return Err(LightningError {
+                                       err: "Rapid Gossip Sync data is more than two weeks old".to_owned(),
+                                       action: ErrorAction::IgnoreError,
+                               }
+                               .into());
                        }
                }
 
@@ -157,7 +170,8 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                                excess_data: Vec::new(),
                                        };
 
-                                       read_only_network_graph.nodes()
+                                       read_only_network_graph
+                                               .nodes()
                                                .get(&current_node_id)
                                                .and_then(|node| node.announcement_info.as_ref())
                                                .map(|info| {
@@ -172,7 +186,8 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                                let mut node_addresses: Vec<SocketAddress> = Vec::new();
                                                for address_index in 0..address_count {
                                                        let current_byte_count: u8 = Readable::read(read_cursor)?;
-                                                       let mut address_reader = FixedLengthReader::new(&mut read_cursor, current_byte_count as u64);
+                                                       let mut address_reader =
+                                                               FixedLengthReader::new(&mut read_cursor, current_byte_count as u64);
                                                        if let Ok(current_address) = Readable::read(&mut address_reader) {
                                                                node_addresses.push(current_address);
                                                                if address_reader.bytes_remain() {
@@ -183,7 +198,8 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                                                log_gossip!(
                                                                        self.logger,
                                                                        "Failure to parse address at index {} for node ID {}",
-                                                                       address_index, current_node_id
+                                                                       address_index,
+                                                                       current_node_id
                                                                );
                                                                address_reader.eat_remaining()?;
                                                        }
@@ -209,7 +225,11 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
 
                                if has_additional_data {
                                        let additional_data: Vec<u8> = Readable::read(read_cursor)?;
-                                       log_gossip!(self.logger, "Ignoring {} bytes of additional data in node announcement", additional_data.len());
+                                       log_gossip!(
+                                               self.logger,
+                                               "Ignoring {} bytes of additional data in node announcement",
+                                               additional_data.len()
+                                       );
                                }
                        }
                } else {
@@ -226,15 +246,15 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
 
                        // handle SCID
                        let scid_delta: BigSize = Readable::read(read_cursor)?;
-                       let short_channel_id = previous_scid
-                               .checked_add(scid_delta.0)
-                               .ok_or(DecodeError::InvalidValue)?;
+                       let short_channel_id =
+                               previous_scid.checked_add(scid_delta.0).ok_or(DecodeError::InvalidValue)?;
                        previous_scid = short_channel_id;
 
                        let node_id_1_index: BigSize = Readable::read(read_cursor)?;
                        let mut node_id_2_index: BigSize = Readable::read(read_cursor)?;
                        let has_additional_data = (node_id_2_index.0 & (1 << 63)) > 0;
-                       node_id_2_index.0 &= !(1 << 63); // ensure 63rd bit isn't set
+                       // ensure 63rd bit isn't set
+                       node_id_2_index.0 &= !(1 << 63);
 
                        if max(node_id_1_index.0, node_id_2_index.0) >= node_id_count as u64 {
                                return Err(DecodeError::InvalidValue.into());
@@ -242,8 +262,12 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                        let node_id_1 = node_ids[node_id_1_index.0 as usize];
                        let node_id_2 = node_ids[node_id_2_index.0 as usize];
 
-                       log_gossip!(self.logger, "Adding channel {} from RGS announcement at {}",
-                               short_channel_id, latest_seen_timestamp);
+                       log_gossip!(
+                               self.logger,
+                               "Adding channel {} from RGS announcement at {}",
+                               short_channel_id,
+                               latest_seen_timestamp
+                       );
 
                        let announcement_result = network_graph.add_channel_from_partial_announcement(
                                short_channel_id,
@@ -256,7 +280,11 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                if let ErrorAction::IgnoreDuplicateGossip = lightning_error.action {
                                        // everything is fine, just a duplicate channel announcement
                                } else {
-                                       log_warn!(self.logger, "Failed to process channel announcement: {:?}", lightning_error);
+                                       log_warn!(
+                                               self.logger,
+                                               "Failed to process channel announcement: {:?}",
+                                               lightning_error
+                                       );
                                        return Err(lightning_error.into());
                                }
                        }
@@ -264,25 +292,35 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                        if version >= 2 && has_additional_data {
                                // forwards compatibility
                                let additional_data: Vec<u8> = Readable::read(read_cursor)?;
-                               log_gossip!(self.logger, "Ignoring {} bytes of additional data in channel announcement", additional_data.len());
+                               log_gossip!(
+                                       self.logger,
+                                       "Ignoring {} bytes of additional data in channel announcement",
+                                       additional_data.len()
+                               );
                        }
                }
 
                for modification in node_modifications {
                        match network_graph.update_node_from_unsigned_announcement(&modification) {
-                               Ok(_) => {}
-                               Err(LightningError { action: ErrorAction::IgnoreDuplicateGossip, .. }) => {}
+                               Ok(_) => {},
+                               Err(LightningError { action: ErrorAction::IgnoreDuplicateGossip, .. }) => {},
                                Err(LightningError { action: ErrorAction::IgnoreAndLog(level), err }) => {
-                                       log_given_level!(self.logger, level, "Failed to apply node announcement: {:?}", err);
-                               }
+                                       log_given_level!(
+                                               self.logger,
+                                               level,
+                                               "Failed to apply node announcement: {:?}",
+                                               err
+                                       );
+                               },
                                Err(LightningError { action: ErrorAction::IgnoreError, err }) => {
                                        log_gossip!(self.logger, "Failed to apply node announcement: {:?}", err);
-                               }
+                               },
                                Err(e) => return Err(e.into()),
                        }
                }
 
-               previous_scid = 0; // updates start at a new scid
+               // updates start at a new scid
+               previous_scid = 0;
 
                let update_count: u32 = Readable::read(read_cursor)?;
                log_debug!(self.logger, "Processing RGS update from {} with {} nodes, {} channel announcements and {} channel updates.",
@@ -302,9 +340,8 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
 
                for _ in 0..update_count {
                        let scid_delta: BigSize = Readable::read(read_cursor)?;
-                       let short_channel_id = previous_scid
-                               .checked_add(scid_delta.0)
-                               .ok_or(DecodeError::InvalidValue)?;
+                       let short_channel_id =
+                               previous_scid.checked_add(scid_delta.0).ok_or(DecodeError::InvalidValue)?;
                        previous_scid = short_channel_id;
 
                        let channel_flags: u8 = Readable::read(read_cursor)?;
@@ -317,7 +354,11 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                if scid_delta.0 == 0 && is_same_direction_update {
                                        // this is additional data for forwards compatibility
                                        let additional_data: Vec<u8> = Readable::read(read_cursor)?;
-                                       log_gossip!(self.logger, "Ignoring {} bytes of additional data in channel update", additional_data.len());
+                                       log_gossip!(
+                                               self.logger,
+                                               "Ignoring {} bytes of additional data in channel update",
+                                               additional_data.len()
+                                       );
                                        continue;
                                }
                        }
@@ -343,15 +384,17 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                        if (channel_flags & 0b_1000_0000) != 0 {
                                // incremental update, field flags will indicate mutated values
                                let read_only_network_graph = network_graph.read_only();
-                               if let Some(directional_info) =
-                                       read_only_network_graph.channels().get(&short_channel_id)
+                               if let Some(directional_info) = read_only_network_graph
+                                       .channels()
+                                       .get(&short_channel_id)
                                        .and_then(|channel| channel.get_directional_info(channel_flags))
                                {
                                        synthetic_update.cltv_expiry_delta = directional_info.cltv_expiry_delta;
                                        synthetic_update.htlc_minimum_msat = directional_info.htlc_minimum_msat;
                                        synthetic_update.htlc_maximum_msat = directional_info.htlc_maximum_msat;
                                        synthetic_update.fee_base_msat = directional_info.fees.base_msat;
-                                       synthetic_update.fee_proportional_millionths = directional_info.fees.proportional_millionths;
+                                       synthetic_update.fee_proportional_millionths =
+                                               directional_info.fees.proportional_millionths;
                                } else {
                                        log_trace!(self.logger,
                                                "Skipping application of channel update for chan {} with flags {} as original data is missing.",
@@ -389,13 +432,23 @@ impl<NG: Deref<Target=NetworkGraph<L>>, L: Deref> RapidGossipSync<NG, L> where L
                                continue;
                        }
 
-                       log_gossip!(self.logger, "Updating channel {} with flags {} from RGS announcement at {}",
-                               short_channel_id, channel_flags, latest_seen_timestamp);
+                       log_gossip!(
+                               self.logger,
+                               "Updating channel {} with flags {} from RGS announcement at {}",
+                               short_channel_id,
+                               channel_flags,
+                               latest_seen_timestamp
+                       );
                        match network_graph.update_channel_unsigned(&synthetic_update) {
                                Ok(_) => {},
                                Err(LightningError { action: ErrorAction::IgnoreDuplicateGossip, .. }) => {},
                                Err(LightningError { action: ErrorAction::IgnoreAndLog(level), err }) => {
-                                       log_given_level!(self.logger, level, "Failed to apply channel update: {:?}", err);
+                                       log_given_level!(
+                                               self.logger,
+                                               level,
+                                               "Failed to apply channel update: {:?}",
+                                               err
+                                       );
                                },
                                Err(LightningError { action: ErrorAction::IgnoreError, .. }) => {},
                                Err(e) => return Err(e.into()),
@@ -429,21 +482,20 @@ mod tests {
        use crate::{GraphSyncError, RapidGossipSync};
 
        const VALID_RGS_BINARY: [u8; 300] = [
-               76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
-               79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218,
-               0, 0, 0, 4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251,
-               187, 172, 38, 46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125,
-               157, 176, 223, 175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136,
-               88, 216, 115, 11, 111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106,
-               204, 131, 186, 35, 93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138,
-               181, 64, 187, 103, 127, 68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175,
-               110, 32, 237, 0, 217, 90, 31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128,
-               76, 97, 0, 0, 0, 2, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68,
-               226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 4, 0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 3, 232,
-               0, 0, 0, 1, 0, 0, 0, 0, 29, 129, 25, 192, 255, 8, 153, 192, 0, 2, 27, 0, 0, 60, 0, 0,
-               0, 0, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 2, 224, 0, 0, 0, 0, 58, 85, 116, 216, 0, 29, 0,
-               0, 0, 1, 0, 0, 0, 125, 0, 0, 0, 0, 58, 85, 116, 216, 255, 2, 68, 226, 0, 6, 11, 0, 1,
-               0, 0, 1,
+               76, 68, 75, 1, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79,
+               147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 97, 227, 98, 218, 0, 0, 0,
+               4, 2, 22, 7, 207, 206, 25, 164, 197, 231, 230, 231, 56, 102, 61, 250, 251, 187, 172, 38,
+               46, 79, 247, 108, 44, 155, 48, 219, 238, 252, 53, 192, 6, 67, 2, 36, 125, 157, 176, 223,
+               175, 234, 116, 94, 248, 201, 225, 97, 235, 50, 47, 115, 172, 63, 136, 88, 216, 115, 11,
+               111, 217, 114, 84, 116, 124, 231, 107, 2, 158, 1, 242, 121, 152, 106, 204, 131, 186, 35,
+               93, 70, 216, 10, 237, 224, 183, 89, 95, 65, 3, 83, 185, 58, 138, 181, 64, 187, 103, 127,
+               68, 50, 2, 201, 19, 17, 138, 136, 149, 185, 226, 156, 137, 175, 110, 32, 237, 0, 217, 90,
+               31, 100, 228, 149, 46, 219, 175, 168, 77, 4, 143, 38, 128, 76, 97, 0, 0, 0, 2, 0, 0, 255,
+               8, 153, 192, 0, 2, 27, 0, 0, 0, 1, 0, 0, 255, 2, 68, 226, 0, 6, 11, 0, 1, 2, 3, 0, 0, 0, 4,
+               0, 40, 0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 3, 232, 0, 0, 0, 1, 0, 0, 0, 0, 29, 129, 25, 192,
+               255, 8, 153, 192, 0, 2, 27, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 100, 0, 0, 2, 224,
+               0, 0, 0, 0, 58, 85, 116, 216, 0, 29, 0, 0, 0, 1, 0, 0, 0, 125, 0, 0, 0, 0, 58, 85, 116,
+               216, 255, 2, 68, 226, 0, 6, 11, 0, 1, 0, 0, 1,
        ];
        const VALID_BINARY_TIMESTAMP: u64 = 1642291930;
 
@@ -489,15 +541,15 @@ mod tests {
                        76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
                        79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 102, 97, 206, 240,
                        0, 0, 0, 0, 2, 63, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5,
-                       101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, 5, 38, 4, 1,
+                       101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, 5, 38, 4,
                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-                       1, 1, 0, 2, 3, 0, 4, 7, 1, 127, 0, 0, 1, 37, 163, 14, 5, 10, 103, 111, 111, 103, 108,
-                       101, 46, 99, 111, 109, 1, 187, 19, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5,
-                       57, 13, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 2, 23, 48, 62, 77, 75, 108, 209,
-                       54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66,
-                       51, 116, 196, 81, 167, 37, 77, 7, 102, 0, 0, 2, 25, 48, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
-                       0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-                       0, 0, 1
+                       1, 1, 1, 0, 2, 3, 0, 4, 7, 1, 127, 0, 0, 1, 37, 163, 14, 5, 10, 103, 111, 111, 103,
+                       108, 101, 46, 99, 111, 109, 1, 187, 19, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                       1, 5, 57, 13, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 2, 23, 48, 62, 77, 75, 108,
+                       209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201,
+                       66, 51, 116, 196, 81, 167, 37, 77, 7, 102, 0, 0, 2, 25, 48, 0, 0, 0, 1, 0, 0, 1, 0, 1,
+                       0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 1, 0, 0, 1,
                ];
 
                let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
@@ -510,7 +562,11 @@ mod tests {
 
                {
                        // address node
-                       let node_id = NodeId::from_slice(&[3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143]).unwrap();
+                       let node_id = NodeId::from_slice(&[
+                               3, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30,
+                               24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
+                       ])
+                       .unwrap();
                        let node = nodes.get(&node_id).unwrap();
                        let announcement_info = node.announcement_info.as_ref().unwrap();
                        let addresses = announcement_info.addresses();
@@ -519,7 +575,11 @@ mod tests {
 
                {
                        // feature node
-                       let node_id = NodeId::from_slice(&[2, 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102]).unwrap();
+                       let node_id = NodeId::from_slice(&[
+                               2, 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217,
+                               234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
+                       ])
+                       .unwrap();
                        let node = nodes.get(&node_id).unwrap();
                        let announcement_info = node.announcement_info.as_ref().unwrap();
                        let features = announcement_info.features();
@@ -527,7 +587,11 @@ mod tests {
                        // assert_eq!(addresses.len(), 5);
                }
 
-               logger.assert_log_contains("lightning_rapid_gossip_sync::processing", "Failed to apply node announcement", 0);
+               logger.assert_log_contains(
+                       "lightning_rapid_gossip_sync::processing",
+                       "Failed to apply node announcement",
+                       0,
+               );
        }
 
        #[test]
@@ -538,13 +602,25 @@ mod tests {
                let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
 
                let example_input = vec![
-                       76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 102, 105, 183, 240, 0, 0, 0, 0, 1, 63, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, 5, 13, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 7, 1, 127, 0, 0, 1, 37, 163, 19, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 57, 38, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 3, 0, 4, 14, 5, 10, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 1, 187, 0, 2, 23, 48, 0, 0, 0, 0, 0, 0, 0, 0,
+                       76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
+                       79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 102, 105, 183,
+                       240, 0, 0, 0, 0, 1, 63, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186,
+                       5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, 5, 13,
+                       3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 7, 1, 127, 0, 0, 1, 37, 163, 19, 2, 1, 1, 1,
+                       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 57, 38, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 3, 0, 4, 14, 5,
+                       10, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 1, 187, 0, 2, 23, 48, 0, 0, 0, 0,
+                       0, 0, 0, 0,
                ];
 
                let update_result = rapid_sync.update_network_graph_no_std(&example_input[..], None);
                assert!(update_result.is_ok());
 
-               logger.assert_log_contains("lightning_rapid_gossip_sync::processing", "Failed to apply node announcement: \"No existing channels for node_announcement\"", 1);
+               logger.assert_log_contains(
+                       "lightning_rapid_gossip_sync::processing",
+                       "Failed to apply node announcement: \"No existing channels for node_announcement\"",
+                       1,
+               );
        }
 
        #[test]
@@ -558,11 +634,12 @@ mod tests {
                        76, 68, 75, 2, 111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247,
                        79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0, 102, 106, 12, 80,
                        1, 0, 2, 23, 48, 0, 0, 0, 3, 143, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213,
-                       170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
-                       5, 38, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-                       1, 1, 1, 1, 1, 1, 0, 2, 3, 0, 4, 19, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-                       5, 57, 13, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 7, 1, 127, 0, 0, 1, 37, 163, 14, 5,
-                       10, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 1, 187, 0, 255, 0, 0, 0, 0, 0, 0, 0,
+                       170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7,
+                       143, 5, 38, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                       1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 3, 0, 4, 19, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+                       1, 1, 5, 57, 13, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 7, 1, 127, 0, 0, 1, 37, 163,
+                       14, 5, 10, 103, 111, 111, 103, 108, 101, 46, 99, 111, 109, 1, 187, 0, 255, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -570,10 +647,10 @@ mod tests {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 77, 75, 108, 209, 54, 16,
+                       50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116,
+                       196, 81, 167, 37, 77, 7, 102, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 77, 75, 108, 209, 54, 16, 50, 202,
-                       155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116, 196, 81,
-                       167, 37, 77, 7, 102, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -581,10 +658,10 @@ mod tests {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 186, 83, 31, 230, 6, 129, 52, 80, 61, 39, 35, 19, 50, 39, 200,
+                       103, 172, 143, 166, 200, 60, 83, 126, 154, 68, 195, 197, 189, 189, 203, 31, 227, 55, 0,
+                       2, 22, 49, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                       0, 0, 0, 186, 83, 31, 230, 6, 129, 52, 80, 61, 39, 35, 19, 50, 39, 200, 103, 172, 143,
-                       166, 200, 60, 83, 126, 154, 68, 195, 197, 189, 189, 203, 31, 227, 55, 0, 2, 22, 49, 0,
-                       255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -592,26 +669,37 @@ mod tests {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-                       0, 0, 1, 0, 255, 128, 0, 0, 0, 0, 0, 0, 1, 0, 147, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+                       0, 0, 0, 1, 0, 0, 1, 0, 255, 128, 0, 0, 0, 0, 0, 0, 1, 0, 147, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
                        23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
-                       23, 23, 23, 23, 23, 23, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
-                       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 17, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-                       42, 42, 42, 42, 42, 42, 42, 0, 1, 0, 1, 0, 17, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-                       42, 42, 42, 42, 42, 42, 42
+                       23, 23, 23, 23, 23, 23, 23, 23, 23, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 17, 42, 42, 42, 42, 42, 42, 42,
+                       42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 0, 1, 0, 1, 0, 17, 42, 42, 42, 42, 42, 42, 42,
+                       42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
                ];
 
                let update_result = rapid_sync.update_network_graph_no_std(&example_input[..], None);
                assert!(update_result.is_ok());
 
-               logger.assert_log_contains("lightning_rapid_gossip_sync::processing", "Ignoring 255 bytes of additional data in node announcement", 3);
-               logger.assert_log_contains("lightning_rapid_gossip_sync::processing", "Ignoring 147 bytes of additional data in channel announcement", 1);
-               logger.assert_log_contains("lightning_rapid_gossip_sync::processing", "Ignoring 17 bytes of additional data in channel update", 1);
+               logger.assert_log_contains(
+                       "lightning_rapid_gossip_sync::processing",
+                       "Ignoring 255 bytes of additional data in node announcement",
+                       3,
+               );
+               logger.assert_log_contains(
+                       "lightning_rapid_gossip_sync::processing",
+                       "Ignoring 147 bytes of additional data in channel announcement",
+                       1,
+               );
+               logger.assert_log_contains(
+                       "lightning_rapid_gossip_sync::processing",
+                       "Ignoring 17 bytes of additional data in channel update",
+                       1,
+               );
        }
 
        #[test]
@@ -690,10 +778,7 @@ mod tests {
                let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
                let initialization_result = rapid_sync.update_network_graph(&initialization_input[..]);
                if initialization_result.is_err() {
-                       panic!(
-                               "Unexpected initialization result: {:?}",
-                               initialization_result
-                       )
+                       panic!("Unexpected initialization result: {:?}", initialization_result)
                }
 
                assert_eq!(network_graph.read_only().channels().len(), 2);
@@ -756,7 +841,8 @@ mod tests {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 136, 0, 0, 0, 221, 255, 2,
                        68, 226, 0, 6, 11, 0, 1, 128,
                ];
-               let update_result = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
+               let update_result =
+                       rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
                if update_result.is_err() {
                        panic!("Unexpected update result: {:?}", update_result)
                }
@@ -816,9 +902,11 @@ mod tests {
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 8, 153, 192, 0, 2, 27, 0, 0, 136, 0, 0, 0, 221, 255, 2,
                        68, 226, 0, 6, 11, 0, 1, 128,
                ];
-               let update_result_1 = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
+               let update_result_1 =
+                       rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
                // Apply duplicate update
-               let update_result_2 = rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
+               let update_result_2 =
+                       rapid_sync.update_network_graph(&single_direction_incremental_update_input[..]);
                assert!(update_result_1.is_ok());
                assert!(update_result_2.is_ok());
        }
@@ -881,7 +969,8 @@ mod tests {
                        assert_eq!(network_graph.read_only().channels().len(), 0);
 
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
-                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time));
+                       let update_result = rapid_sync
+                               .update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time));
                        assert!(update_result.is_ok());
                        assert_eq!(network_graph.read_only().channels().len(), 2);
                }
@@ -891,7 +980,8 @@ mod tests {
                        assert_eq!(network_graph.read_only().channels().len(), 0);
 
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
-                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time + 1));
+                       let update_result = rapid_sync
+                               .update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_nonpruning_time + 1));
                        assert!(update_result.is_ok());
                        assert_eq!(network_graph.read_only().channels().len(), 0);
                }
@@ -910,7 +1000,8 @@ mod tests {
                        assert_eq!(network_graph.read_only().channels().len(), 0);
 
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
-                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_succeeding_time));
+                       let update_result = rapid_sync
+                               .update_network_graph_no_std(&VALID_RGS_BINARY, Some(latest_succeeding_time));
                        assert!(update_result.is_ok());
                        assert_eq!(network_graph.read_only().channels().len(), 0);
                }
@@ -920,7 +1011,8 @@ mod tests {
                        assert_eq!(network_graph.read_only().channels().len(), 0);
 
                        let rapid_sync = RapidGossipSync::new(&network_graph, &logger);
-                       let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(earliest_failing_time));
+                       let update_result = rapid_sync
+                               .update_network_graph_no_std(&VALID_RGS_BINARY, Some(earliest_failing_time));
                        assert!(update_result.is_err());
                        if let Err(GraphSyncError::LightningError(lightning_error)) = update_result {
                                assert_eq!(
@@ -980,7 +1072,10 @@ mod tests {
                let update_result = rapid_sync.update_network_graph_no_std(&VALID_RGS_BINARY, Some(0));
                assert!(update_result.is_err());
                if let Err(GraphSyncError::LightningError(err)) = update_result {
-                       assert_eq!(err.err, "Rapid Gossip Sync data's chain hash does not match the network graph's");
+                       assert_eq!(
+                               err.err,
+                               "Rapid Gossip Sync data's chain hash does not match the network graph's"
+                       );
                } else {
                        panic!("Unexpected update result: {:?}", update_result)
                }
index 1f3f5a1fa38e70bdac2c7d01923fa06e04513f2e..bdbb4be4541d2ce8f3aa34840263de963b23ec57 100644 (file)
@@ -30,7 +30,7 @@ use core::mem;
 use core::ops::Deref;
 
 /// An intermediate node, and possibly a short channel id leading to the next node.
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
 pub struct ForwardNode {
        /// This node's pubkey.
        pub node_id: PublicKey,
@@ -106,6 +106,8 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
 
 // Advance the blinded onion message path by one hop, so make the second hop into the new
 // introduction node.
+//
+// Will only modify `path` when returning `Ok`.
 pub(crate) fn advance_path_by_one<NS: Deref, NL: Deref, T>(
        path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
 ) -> Result<(), ()>
@@ -116,8 +118,8 @@ where
 {
        let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
        let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
-       let encrypted_control_tlvs = path.blinded_hops.remove(0).encrypted_payload;
-       let mut s = Cursor::new(&encrypted_control_tlvs);
+       let encrypted_control_tlvs = &path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
+       let mut s = Cursor::new(encrypted_control_tlvs);
        let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
        match ChaChaPolyReadAdapter::read(&mut reader, rho) {
                Ok(ChaChaPolyReadAdapter {
@@ -139,6 +141,7 @@ where
                        };
                        mem::swap(&mut path.blinding_point, &mut new_blinding_point);
                        path.introduction_node = IntroductionNode::NodeId(next_node_id);
+                       path.blinded_hops.remove(0);
                        Ok(())
                },
                _ => Err(())
index 3b71f77c6d5f8488593468fa8f57fcba33af8f30..7df7d1c63edd1ed8222b2b9e470b235671d14d82 100644 (file)
 
 use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
 
-use crate::blinded_path::BlindedHop;
+use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
 use crate::blinded_path::utils;
+use crate::crypto::streams::ChaChaPolyReadAdapter;
 use crate::io;
+use crate::io::Cursor;
 use crate::ln::types::PaymentSecret;
 use crate::ln::channel_state::CounterpartyForwardingInfo;
 use crate::ln::features::BlindedHopFeatures;
 use crate::ln::msgs::DecodeError;
+use crate::ln::onion_utils;
 use crate::offers::invoice::BlindedPayInfo;
 use crate::offers::invoice_request::InvoiceRequestFields;
 use crate::offers::offer::OfferId;
-use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
+use crate::sign::{NodeSigner, Recipient};
+use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer};
+
+use core::mem;
+use core::ops::Deref;
 
 #[allow(unused_imports)]
 use crate::prelude::*;
@@ -274,6 +281,43 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
        utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
 }
 
+// Advance the blinded onion payment path by one hop, so make the second hop into the new
+// introduction node.
+//
+// Will only modify `path` when returning `Ok`.
+pub(crate) fn advance_path_by_one<NS: Deref, NL: Deref, T>(
+       path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1<T>
+) -> Result<(), ()>
+where
+       NS::Target: NodeSigner,
+       NL::Target: NodeIdLookUp,
+       T: secp256k1::Signing + secp256k1::Verification,
+{
+       let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?;
+       let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
+       let encrypted_control_tlvs = &path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
+       let mut s = Cursor::new(encrypted_control_tlvs);
+       let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
+       match ChaChaPolyReadAdapter::read(&mut reader, rho) {
+               Ok(ChaChaPolyReadAdapter {
+                       readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. })
+               }) => {
+                       let next_node_id = match node_id_lookup.next_node_id(short_channel_id) {
+                               Some(node_id) => node_id,
+                               None => return Err(()),
+                       };
+                       let mut new_blinding_point = onion_utils::next_hop_pubkey(
+                               secp_ctx, path.blinding_point, control_tlvs_ss.as_ref()
+                       ).map_err(|_| ())?;
+                       mem::swap(&mut path.blinding_point, &mut new_blinding_point);
+                       path.introduction_node = IntroductionNode::NodeId(next_node_id);
+                       path.blinded_hops.remove(0);
+                       Ok(())
+               },
+               _ => Err(())
+       }
+}
+
 /// `None` if underflow occurs.
 pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option<u64> {
        let inbound_amt = inbound_amt_msat as u128;
index c6d1bcdd2158025fa11984aa32f5207380d459cd..0e87f3569e605d0c25736a9d203bc1fe6170655f 100644 (file)
@@ -1930,9 +1930,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
        }
 
        #[cfg(test)]
-       pub fn do_signer_call<F: FnMut(&Signer) -> ()>(&self, mut f: F) {
-               let inner = self.inner.lock().unwrap();
-               f(&inner.onchain_tx_handler.signer);
+       pub fn do_mut_signer_call<F: FnMut(&mut Signer) -> ()>(&self, mut f: F) {
+               let mut inner = self.inner.lock().unwrap();
+               f(&mut inner.onchain_tx_handler.signer);
        }
 }
 
index a1d1b3aa572470bda0bf984a7f07380648ad8e1a..887851864c97e84f62a7502673cd37e2259d316a 100644 (file)
@@ -789,6 +789,8 @@ pub enum Event {
                /// If the recipient or an intermediate node misbehaves and gives us free money, this may
                /// overstate the amount paid, though this is unlikely.
                ///
+               /// This is only `None` for payments initiated on LDK versions prior to 0.0.103.
+               ///
                /// [`Route::get_total_fees`]: crate::routing::router::Route::get_total_fees
                fee_paid_msat: Option<u64>,
        },
index 8e929fe844da41df6d17deabc90079ad3b6a37e8..b6e5a222d272c9d576f92956e87154ce9d03033b 100644 (file)
@@ -20,6 +20,7 @@ use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureR
 use crate::ln::functional_test_utils::*;
 use crate::ln::msgs::ChannelMessageHandler;
 use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
+use crate::util::test_channel_signer::SignerOp;
 
 #[test]
 fn test_async_commitment_signature_for_funding_created() {
@@ -43,7 +44,7 @@ fn test_async_commitment_signature_for_funding_created() {
        // But! Let's make node[0]'s signer be unavailable: we should *not* broadcast a funding_created
        // message...
        let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 100000, 42);
-       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &temporary_channel_id, false);
+       nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
        nodes[0].node.funding_transaction_generated(&temporary_channel_id, &nodes[1].node.get_our_node_id(), tx.clone()).unwrap();
        check_added_monitors(&nodes[0], 0);
 
@@ -57,7 +58,7 @@ fn test_async_commitment_signature_for_funding_created() {
                channels[0].channel_id
        };
 
-       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, true);
+       nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        nodes[0].node.signer_unblocked(Some((nodes[1].node.get_our_node_id(), chan_id)));
 
        let mut funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
@@ -98,7 +99,7 @@ fn test_async_commitment_signature_for_funding_signed() {
 
        // Now let's make node[1]'s signer be unavailable while handling the `funding_created`. It should
        // *not* broadcast a `funding_signed`...
-       nodes[1].set_channel_signer_available(&nodes[0].node.get_our_node_id(), &temporary_channel_id, false);
+       nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
        nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msg);
        check_added_monitors(&nodes[1], 1);
 
@@ -111,7 +112,7 @@ fn test_async_commitment_signature_for_funding_signed() {
                assert_eq!(channels.len(), 1, "expected one channel, not {}", channels.len());
                channels[0].channel_id
        };
-       nodes[1].set_channel_signer_available(&nodes[0].node.get_our_node_id(), &chan_id, true);
+       nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
 
        expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
@@ -152,14 +153,14 @@ fn test_async_commitment_signature_for_commitment_signed() {
 
        // Mark dst's signer as unavailable and handle src's commitment_signed: while dst won't yet have a
        // `commitment_signed` of its own to offer, it should publish a `revoke_and_ack`.
-       dst.set_channel_signer_available(&src.node.get_our_node_id(), &chan_id, false);
+       dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
        check_added_monitors(dst, 1);
 
        get_event_msg!(dst, MessageSendEvent::SendRevokeAndACK, src.node.get_our_node_id());
 
        // Mark dst's signer as available and retry: we now expect to see dst's `commitment_signed`.
-       dst.set_channel_signer_available(&src.node.get_our_node_id(), &chan_id, true);
+       dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
 
        let events = dst.node.get_and_clear_pending_msg_events();
@@ -215,7 +216,7 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
 
        // Now let's make node[1]'s signer be unavailable while handling the `funding_created`. It should
        // *not* broadcast a `funding_signed`...
-       nodes[1].set_channel_signer_available(&nodes[0].node.get_our_node_id(), &temporary_channel_id, false);
+       nodes[1].disable_channel_signer_op(&nodes[0].node.get_our_node_id(), &temporary_channel_id, SignerOp::SignCounterpartyCommitment);
        nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created_msg);
        check_added_monitors(&nodes[1], 1);
 
@@ -230,7 +231,7 @@ fn test_async_commitment_signature_for_funding_signed_0conf() {
        };
 
        // At this point, we basically expect the channel to open like a normal zero-conf channel.
-       nodes[1].set_channel_signer_available(&nodes[0].node.get_our_node_id(), &chan_id, true);
+       nodes[1].enable_channel_signer_op(&nodes[0].node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        nodes[1].node.signer_unblocked(Some((nodes[0].node.get_our_node_id(), chan_id)));
 
        let (funding_signed, channel_ready_1) = {
@@ -299,7 +300,7 @@ fn test_async_commitment_signature_for_peer_disconnect() {
 
        // Mark dst's signer as unavailable and handle src's commitment_signed: while dst won't yet have a
        // `commitment_signed` of its own to offer, it should publish a `revoke_and_ack`.
-       dst.set_channel_signer_available(&src.node.get_our_node_id(), &chan_id, false);
+       dst.disable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        dst.node.handle_commitment_signed(&src.node.get_our_node_id(), &payment_event.commitment_msg);
        check_added_monitors(dst, 1);
 
@@ -314,7 +315,7 @@ fn test_async_commitment_signature_for_peer_disconnect() {
        reconnect_nodes(reconnect_args);
 
        // Mark dst's signer as available and retry: we now expect to see dst's `commitment_signed`.
-       dst.set_channel_signer_available(&src.node.get_our_node_id(), &chan_id, true);
+       dst.enable_channel_signer_op(&src.node.get_our_node_id(), &chan_id, SignerOp::SignCounterpartyCommitment);
        dst.node.signer_unblocked(Some((src.node.get_our_node_id(), chan_id)));
 
        {
@@ -366,7 +367,6 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
        route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
        let error_message = "Channel force-closed";
 
-       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, false);
 
        if remote_commitment {
                // Make the counterparty broadcast its latest commitment.
@@ -375,6 +375,8 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
                check_closed_broadcast(&nodes[1], 1, true);
                check_closed_event(&nodes[1], 1, ClosureReason::HolderForceClosed { broadcasted_latest_txn: Some(true) }, false, &[nodes[0].node.get_our_node_id()], 100_000);
        } else {
+               nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderCommitment);
+               nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderHtlcTransaction);
                // We'll connect blocks until the sender has to go onchain to time out the HTLC.
                connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
 
@@ -383,7 +385,8 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
                assert!(nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
 
                // Mark it as available now, we should see the signed commitment transaction.
-               nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, true);
+               nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderCommitment);
+               nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderHtlcTransaction);
                get_monitor!(nodes[0], chan_id).signer_unblocked(nodes[0].tx_broadcaster, nodes[0].fee_estimator, &nodes[0].logger);
        }
 
@@ -409,7 +412,13 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
 
        // Mark it as unavailable again to now test the HTLC transaction. We'll mine the commitment such
        // that the HTLC transaction is retried.
-       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, false);
+       let sign_htlc_op = if remote_commitment {
+               SignerOp::SignCounterpartyHtlcTransaction
+       } else {
+               SignerOp::SignHolderHtlcTransaction
+       };
+       nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderCommitment);
+       nodes[0].disable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, sign_htlc_op);
        mine_transaction(&nodes[0], &commitment_tx);
 
        check_added_monitors(&nodes[0], 1);
@@ -426,10 +435,12 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
        if anchors && !remote_commitment {
                handle_bump_htlc_event(&nodes[0], 1);
        }
-       assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
+       let txn = nodes[0].tx_broadcaster.txn_broadcast();
+       assert!(txn.is_empty(), "expected no transaction to be broadcast, got {:?}", txn);
 
        // Mark it as available now, we should see the signed HTLC transaction.
-       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, true);
+       nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, SignerOp::SignHolderCommitment);
+       nodes[0].enable_channel_signer_op(&nodes[1].node.get_our_node_id(), &chan_id, sign_htlc_op);
        get_monitor!(nodes[0], chan_id).signer_unblocked(nodes[0].tx_broadcaster, nodes[0].fee_estimator, &nodes[0].logger);
 
        if anchors && !remote_commitment {
@@ -443,9 +454,21 @@ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
 }
 
 #[test]
-fn test_async_holder_signatures() {
+fn test_async_holder_signatures_no_anchors() {
        do_test_async_holder_signatures(false, false);
+}
+
+#[test]
+fn test_async_holder_signatures_remote_commitment_no_anchors() {
        do_test_async_holder_signatures(false, true);
+}
+
+#[test]
+fn test_async_holder_signatures_anchors() {
        do_test_async_holder_signatures(true, false);
+}
+
+#[test]
+fn test_async_holder_signatures_remote_commitment_anchors() {
        do_test_async_holder_signatures(true, true);
 }
index 493607639f5e9d15935c192b1f83cdddbb004e82..ce07cb73713aff10e222a4a55775b2edbcd7bcf6 100644 (file)
@@ -1612,7 +1612,10 @@ fn test_monitor_update_fail_claim() {
        let (payment_preimage_1, payment_hash_1, ..) = route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
 
        chanmon_cfgs[1].persister.set_update_ret(ChannelMonitorUpdateStatus::InProgress);
+       // As long as the preimage isn't on-chain, we shouldn't expose the `PaymentClaimed` event to
+       // users nor send the preimage to peers in the new commitment update.
        nodes[1].node.claim_funds(payment_preimage_1);
+       assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
        assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
        check_added_monitors!(nodes[1], 1);
 
index b8bccc63cae447a88701c15bdf6c217d149258aa..f5c47260f6ef68842a0ff1c0d03e2935aa4a7560 100644 (file)
@@ -2118,8 +2118,8 @@ impl<SP: Deref> ChannelContext<SP> where SP::Target: SignerProvider  {
 
        /// Returns the holder signer for this channel.
        #[cfg(test)]
-       pub fn get_signer(&self) -> &ChannelSignerType<SP> {
-               return &self.holder_signer
+       pub fn get_mut_signer(&mut self) -> &mut ChannelSignerType<SP> {
+               return &mut self.holder_signer
        }
 
        /// Only allowed immediately after deserialization if get_outbound_scid_alias returns 0,
index 508d13a15822acffe1fc7a5d2decfd333632275f..c2dcf31f2aea5fc5818888f2de0c98a772b3b133 100644 (file)
@@ -4031,8 +4031,8 @@ where
                self.pending_outbound_payments
                        .send_payment_for_bolt12_invoice(
                                invoice, payment_id, &self.router, self.list_usable_channels(),
-                               || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer,
-                               best_block_height, &self.logger, &self.pending_events,
+                               || self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, &self,
+                               &self.secp_ctx, best_block_height, &self.logger, &self.pending_events,
                                |args| self.send_payment_along_path(args)
                        )
        }
@@ -4895,8 +4895,8 @@ where
                                if short_chan_id != 0 {
                                        let mut forwarding_counterparty = None;
                                        macro_rules! forwarding_channel_not_found {
-                                               () => {
-                                                       for forward_info in pending_forwards.drain(..) {
+                                               ($forward_infos: expr) => {
+                                                       for forward_info in $forward_infos {
                                                                match forward_info {
                                                                        HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
                                                                                prev_short_channel_id, prev_htlc_id, prev_channel_id, prev_funding_outpoint,
@@ -5004,7 +5004,7 @@ where
                                        let (counterparty_node_id, forward_chan_id) = match chan_info_opt {
                                                Some((cp_id, chan_id)) => (cp_id, chan_id),
                                                None => {
-                                                       forwarding_channel_not_found!();
+                                                       forwarding_channel_not_found!(pending_forwards.drain(..));
                                                        continue;
                                                }
                                        };
@@ -5012,96 +5012,148 @@ where
                                        let per_peer_state = self.per_peer_state.read().unwrap();
                                        let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
                                        if peer_state_mutex_opt.is_none() {
-                                               forwarding_channel_not_found!();
+                                               forwarding_channel_not_found!(pending_forwards.drain(..));
                                                continue;
                                        }
                                        let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
                                        let peer_state = &mut *peer_state_lock;
-                                       if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
-                                               let logger = WithChannelContext::from(&self.logger, &chan.context, None);
-                                               for forward_info in pending_forwards.drain(..) {
-                                                       let queue_fail_htlc_res = match forward_info {
-                                                               HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
-                                                                       prev_short_channel_id, prev_htlc_id, prev_channel_id, prev_funding_outpoint,
-                                                                       prev_user_channel_id, forward_info: PendingHTLCInfo {
-                                                                               incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
-                                                                               routing: PendingHTLCRouting::Forward {
-                                                                                       onion_packet, blinded, ..
-                                                                               }, skimmed_fee_msat, ..
+                                       let mut draining_pending_forwards = pending_forwards.drain(..);
+                                       while let Some(forward_info) = draining_pending_forwards.next() {
+                                               let queue_fail_htlc_res = match forward_info {
+                                                       HTLCForwardInfo::AddHTLC(PendingAddHTLCInfo {
+                                                               prev_short_channel_id, prev_htlc_id, prev_channel_id, prev_funding_outpoint,
+                                                               prev_user_channel_id, forward_info: PendingHTLCInfo {
+                                                                       incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
+                                                                       routing: PendingHTLCRouting::Forward {
+                                                                               ref onion_packet, blinded, ..
+                                                                       }, skimmed_fee_msat, ..
+                                                               },
+                                                       }) => {
+                                                               let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
+                                                                       short_channel_id: prev_short_channel_id,
+                                                                       user_channel_id: Some(prev_user_channel_id),
+                                                                       channel_id: prev_channel_id,
+                                                                       outpoint: prev_funding_outpoint,
+                                                                       htlc_id: prev_htlc_id,
+                                                                       incoming_packet_shared_secret: incoming_shared_secret,
+                                                                       // Phantom payments are only PendingHTLCRouting::Receive.
+                                                                       phantom_shared_secret: None,
+                                                                       blinded_failure: blinded.map(|b| b.failure),
+                                                               });
+                                                               let next_blinding_point = blinded.and_then(|b| {
+                                                                       let encrypted_tlvs_ss = self.node_signer.ecdh(
+                                                                               Recipient::Node, &b.inbound_blinding_point, None
+                                                                       ).unwrap().secret_bytes();
+                                                                       onion_utils::next_hop_pubkey(
+                                                                               &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss
+                                                                       ).ok()
+                                                               });
+
+                                                               // Forward the HTLC over the most appropriate channel with the corresponding peer,
+                                                               // applying non-strict forwarding.
+                                                               // The channel with the least amount of outbound liquidity will be used to maximize the
+                                                               // probability of being able to successfully forward a subsequent HTLC.
+                                                               let maybe_optimal_channel = peer_state.channel_by_id.values_mut().filter_map(|phase| match phase {
+                                                                       ChannelPhase::Funded(chan) => {
+                                                                               let balances = chan.context.get_available_balances(&self.fee_estimator);
+                                                                               if outgoing_amt_msat <= balances.next_outbound_htlc_limit_msat &&
+                                                                                       outgoing_amt_msat >= balances.next_outbound_htlc_minimum_msat &&
+                                                                                       chan.context.is_usable() {
+                                                                                       Some((chan, balances))
+                                                                               } else {
+                                                                                       None
+                                                                               }
                                                                        },
-                                                               }) => {
-                                                                       let logger = WithChannelContext::from(&self.logger, &chan.context, Some(payment_hash));
-                                                                       log_trace!(logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, &payment_hash, short_chan_id);
-                                                                       let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
-                                                                               short_channel_id: prev_short_channel_id,
-                                                                               user_channel_id: Some(prev_user_channel_id),
-                                                                               channel_id: prev_channel_id,
-                                                                               outpoint: prev_funding_outpoint,
-                                                                               htlc_id: prev_htlc_id,
-                                                                               incoming_packet_shared_secret: incoming_shared_secret,
-                                                                               // Phantom payments are only PendingHTLCRouting::Receive.
-                                                                               phantom_shared_secret: None,
-                                                                               blinded_failure: blinded.map(|b| b.failure),
-                                                                       });
-                                                                       let next_blinding_point = blinded.and_then(|b| {
-                                                                               let encrypted_tlvs_ss = self.node_signer.ecdh(
-                                                                                       Recipient::Node, &b.inbound_blinding_point, None
-                                                                               ).unwrap().secret_bytes();
-                                                                               onion_utils::next_hop_pubkey(
-                                                                                       &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss
-                                                                               ).ok()
-                                                                       });
-                                                                       if let Err(e) = chan.queue_add_htlc(outgoing_amt_msat,
-                                                                               payment_hash, outgoing_cltv_value, htlc_source.clone(),
-                                                                               onion_packet, skimmed_fee_msat, next_blinding_point, &self.fee_estimator,
-                                                                               &&logger)
-                                                                       {
-                                                                               if let ChannelError::Ignore(msg) = e {
-                                                                                       log_trace!(logger, "Failed to forward HTLC with payment_hash {}: {}", &payment_hash, msg);
+                                                                       _ => None,
+                                                               }).min_by_key(|(_, balances)| balances.next_outbound_htlc_limit_msat).map(|(c, _)| c);
+                                                               let optimal_channel = match maybe_optimal_channel {
+                                                                       Some(chan) => chan,
+                                                                       None => {
+                                                                               // Fall back to the specified channel to return an appropriate error.
+                                                                               if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
+                                                                                       chan
                                                                                } else {
-                                                                                       panic!("Stated return value requirements in send_htlc() were not met");
+                                                                                       forwarding_channel_not_found!(core::iter::once(forward_info).chain(draining_pending_forwards));
+                                                                                       break;
                                                                                }
+                                                                       }
+                                                               };
+
+                                                               let logger = WithChannelContext::from(&self.logger, &optimal_channel.context, Some(payment_hash));
+                                                               let channel_description = if optimal_channel.context.get_short_channel_id() == Some(short_chan_id) {
+                                                                       "specified"
+                                                               } else {
+                                                                       "alternate"
+                                                               };
+                                                               log_trace!(logger, "Forwarding HTLC from SCID {} with payment_hash {} and next hop SCID {} over {} channel {} with corresponding peer {}",
+                                                                       prev_short_channel_id, &payment_hash, short_chan_id, channel_description, optimal_channel.context.channel_id(), &counterparty_node_id);
+                                                               if let Err(e) = optimal_channel.queue_add_htlc(outgoing_amt_msat,
+                                                                               payment_hash, outgoing_cltv_value, htlc_source.clone(),
+                                                                               onion_packet.clone(), skimmed_fee_msat, next_blinding_point, &self.fee_estimator,
+                                                                               &&logger)
+                                                               {
+                                                                       if let ChannelError::Ignore(msg) = e {
+                                                                               log_trace!(logger, "Failed to forward HTLC with payment_hash {} to peer {}: {}", &payment_hash, &counterparty_node_id, msg);
+                                                                       } else {
+                                                                               panic!("Stated return value requirements in send_htlc() were not met");
+                                                                       }
+
+                                                                       if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
                                                                                let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, short_chan_id, chan);
                                                                                failed_forwards.push((htlc_source, payment_hash,
                                                                                        HTLCFailReason::reason(failure_code, data),
                                                                                        HTLCDestination::NextHopChannel { node_id: Some(chan.context.get_counterparty_node_id()), channel_id: forward_chan_id }
                                                                                ));
-                                                                               continue;
+                                                                       } else {
+                                                                               forwarding_channel_not_found!(core::iter::once(forward_info).chain(draining_pending_forwards));
+                                                                               break;
                                                                        }
-                                                                       None
-                                                               },
-                                                               HTLCForwardInfo::AddHTLC { .. } => {
-                                                                       panic!("short_channel_id != 0 should imply any pending_forward entries are of type Forward");
-                                                               },
-                                                               HTLCForwardInfo::FailHTLC { htlc_id, err_packet } => {
+                                                               }
+                                                               None
+                                                       },
+                                                       HTLCForwardInfo::AddHTLC { .. } => {
+                                                               panic!("short_channel_id != 0 should imply any pending_forward entries are of type Forward");
+                                                       },
+                                                       HTLCForwardInfo::FailHTLC { htlc_id, ref err_packet } => {
+                                                               if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
+                                                                       let logger = WithChannelContext::from(&self.logger, &chan.context, None);
                                                                        log_trace!(logger, "Failing HTLC back to channel with short id {} (backward HTLC ID {}) after delay", short_chan_id, htlc_id);
-                                                                       Some((chan.queue_fail_htlc(htlc_id, err_packet, &&logger), htlc_id))
-                                                               },
-                                                               HTLCForwardInfo::FailMalformedHTLC { htlc_id, failure_code, sha256_of_onion } => {
+                                                                       Some((chan.queue_fail_htlc(htlc_id, err_packet.clone(), &&logger), htlc_id))
+                                                               } else {
+                                                                       forwarding_channel_not_found!(core::iter::once(forward_info).chain(draining_pending_forwards));
+                                                                       break;
+                                                               }
+                                                       },
+                                                       HTLCForwardInfo::FailMalformedHTLC { htlc_id, failure_code, sha256_of_onion } => {
+                                                               if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
+                                                                       let logger = WithChannelContext::from(&self.logger, &chan.context, None);
                                                                        log_trace!(logger, "Failing malformed HTLC back to channel with short id {} (backward HTLC ID {}) after delay", short_chan_id, htlc_id);
                                                                        let res = chan.queue_fail_malformed_htlc(
                                                                                htlc_id, failure_code, sha256_of_onion, &&logger
                                                                        );
                                                                        Some((res, htlc_id))
-                                                               },
-                                                       };
-                                                       if let Some((queue_fail_htlc_res, htlc_id)) = queue_fail_htlc_res {
-                                                               if let Err(e) = queue_fail_htlc_res {
-                                                                       if let ChannelError::Ignore(msg) = e {
+                                                               } else {
+                                                                       forwarding_channel_not_found!(core::iter::once(forward_info).chain(draining_pending_forwards));
+                                                                       break;
+                                                               }
+                                                       },
+                                               };
+                                               if let Some((queue_fail_htlc_res, htlc_id)) = queue_fail_htlc_res {
+                                                       if let Err(e) = queue_fail_htlc_res {
+                                                               if let ChannelError::Ignore(msg) = e {
+                                                                       if let Some(ChannelPhase::Funded(ref mut chan)) = peer_state.channel_by_id.get_mut(&forward_chan_id) {
+                                                                               let logger = WithChannelContext::from(&self.logger, &chan.context, None);
                                                                                log_trace!(logger, "Failed to fail HTLC with ID {} backwards to short_id {}: {}", htlc_id, short_chan_id, msg);
-                                                                       } else {
-                                                                               panic!("Stated return value requirements in queue_fail_{{malformed_}}htlc() were not met");
                                                                        }
-                                                                       // fail-backs are best-effort, we probably already have one
-                                                                       // pending, and if not that's OK, if not, the channel is on
-                                                                       // the chain and sending the HTLC-Timeout is their problem.
-                                                                       continue;
+                                                               } else {
+                                                                       panic!("Stated return value requirements in queue_fail_{{malformed_}}htlc() were not met");
                                                                }
+                                                               // fail-backs are best-effort, we probably already have one
+                                                               // pending, and if not that's OK, if not, the channel is on
+                                                               // the chain and sending the HTLC-Timeout is their problem.
+                                                               continue;
                                                        }
                                                }
-                                       } else {
-                                               forwarding_channel_not_found!();
-                                               continue;
                                        }
                                } else {
                                        'next_forwardable_htlc: for forward_info in pending_forwards.drain(..) {
index 7e57f20595a5b05630ace9de66b6a854043c7f56..8c08d37f5f6193e2d1fc932a90e547f9e5593d90 100644 (file)
@@ -31,6 +31,8 @@ use crate::util::errors::APIError;
 use crate::util::logger::Logger;
 use crate::util::scid_utils;
 use crate::util::test_channel_signer::TestChannelSigner;
+#[cfg(test)]
+use crate::util::test_channel_signer::SignerOp;
 use crate::util::test_utils;
 use crate::util::test_utils::{panicking, TestChainMonitor, TestScorer, TestKeysInterface};
 use crate::util::ser::{ReadableArgs, Writeable};
@@ -482,46 +484,74 @@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> {
        pub fn get_block_header(&self, height: u32) -> Header {
                self.blocks.lock().unwrap()[height as usize].0.header
        }
-       /// Changes the channel signer's availability for the specified peer and channel.
+
+       /// Toggles this node's signer to be available for the given signer operation.
+       /// This is useful for testing behavior for restoring an async signer that previously
+       /// could not return a signature immediately.
+       #[cfg(test)]
+       pub fn enable_channel_signer_op(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp) {
+               self.set_channel_signer_ops(peer_id, chan_id, signer_op, true);
+       }
+
+       /// Toggles this node's signer to be unavailable, returning `Err` for the given signer operation.
+       /// This is useful for testing behavior for an async signer that cannot return a signature
+       /// immediately.
+       #[cfg(test)]
+       pub fn disable_channel_signer_op(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp) {
+               self.set_channel_signer_ops(peer_id, chan_id, signer_op, false);
+       }
+
+       /// Changes the channel signer's availability for the specified peer, channel, and signer
+       /// operation.
        ///
-       /// When `available` is set to `true`, the channel signer will behave normally. When set to
-       /// `false`, the channel signer will act like an off-line remote signer and will return `Err` for
-       /// several of the signing methods. Currently, only `get_per_commitment_point` and
-       /// `release_commitment_secret` are affected by this setting.
+       /// For the specified signer operation, when `available` is set to `true`, the channel signer
+       /// will behave normally, returning `Ok`. When set to `false`, and the channel signer will
+       /// act like an off-line remote signer, returning `Err`. This applies to the signer in all
+       /// relevant places, i.e. the channel manager, chain monitor, and the keys manager.
        #[cfg(test)]
-       pub fn set_channel_signer_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, available: bool) {
+       fn set_channel_signer_ops(&self, peer_id: &PublicKey, chan_id: &ChannelId, signer_op: SignerOp, available: bool) {
                use crate::sign::ChannelSigner;
                log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
 
                let per_peer_state = self.node.per_peer_state.read().unwrap();
-               let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
+               let mut chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
 
                let mut channel_keys_id = None;
-               if let Some(chan) = chan_lock.channel_by_id.get(chan_id).map(|phase| phase.context()) {
-                       chan.get_signer().as_ecdsa().unwrap().set_available(available);
+               if let Some(chan) = chan_lock.channel_by_id.get_mut(chan_id).map(|phase| phase.context_mut()) {
+                       let signer = chan.get_mut_signer().as_mut_ecdsa().unwrap();
+                       if available {
+                               signer.enable_op(signer_op);
+                       } else {
+                               signer.disable_op(signer_op);
+                       }
                        channel_keys_id = Some(chan.channel_keys_id);
                }
 
-               let mut monitor = None;
-               for (funding_txo, channel_id) in self.chain_monitor.chain_monitor.list_monitors() {
-                       if *chan_id == channel_id {
-                               monitor = self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok();
-                       }
-               }
+               let monitor = self.chain_monitor.chain_monitor.list_monitors().into_iter()
+                       .find(|(_, channel_id)| *channel_id == *chan_id)
+                       .and_then(|(funding_txo, _)| self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok());
                if let Some(monitor) = monitor {
-                       monitor.do_signer_call(|signer| {
+                       monitor.do_mut_signer_call(|signer| {
                                channel_keys_id = channel_keys_id.or(Some(signer.inner.channel_keys_id()));
-                               signer.set_available(available)
+                               if available {
+                                       signer.enable_op(signer_op);
+                               } else {
+                                       signer.disable_op(signer_op);
+                               }
                        });
                }
 
+               let channel_keys_id = channel_keys_id.unwrap();
+               let mut unavailable_signers_ops = self.keys_manager.unavailable_signers_ops.lock().unwrap();
+               let entry = unavailable_signers_ops.entry(channel_keys_id).or_insert(new_hash_set());
                if available {
-                       self.keys_manager.unavailable_signers.lock().unwrap()
-                               .remove(channel_keys_id.as_ref().unwrap());
+                       entry.remove(&signer_op);
+                       if entry.is_empty() {
+                               unavailable_signers_ops.remove(&channel_keys_id);
+                       }
                } else {
-                       self.keys_manager.unavailable_signers.lock().unwrap()
-                               .insert(channel_keys_id.unwrap());
-               }
+                       entry.insert(signer_op);
+               };
        }
 }
 
index eca43afee8a020b59223a8edaeae26527de5cf9a..52375f723c75ec216241468456a43f5f63a4c69f 100644 (file)
@@ -950,9 +950,12 @@ fn pays_bolt12_invoice_asynchronously() {
        );
 }
 
-/// Fails creating an offer when a blinded path cannot be created without exposing the node's id.
+/// Checks that an offer can be created using an unannounced node as a blinded path's introduction
+/// node. This is only preferred if there are no other options which may indicated either the offer
+/// is intended for the unannounced node or that the node is actually announced (e.g., an LSP) but
+/// the recipient doesn't have a network graph.
 #[test]
-fn fails_creating_offer_without_blinded_paths() {
+fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
@@ -960,15 +963,63 @@ fn fails_creating_offer_without_blinded_paths() {
 
        create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
 
-       match nodes[0].node.create_offer_builder(None) {
-               Ok(_) => panic!("Expected error"),
-               Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
+       let alice = &nodes[0];
+       let alice_id = alice.node.get_our_node_id();
+       let bob = &nodes[1];
+       let bob_id = bob.node.get_our_node_id();
+
+       let offer = alice.node
+               .create_offer_builder(None).unwrap()
+               .amount_msats(10_000_000)
+               .build().unwrap();
+       assert_ne!(offer.signing_pubkey(), Some(alice_id));
+       assert!(!offer.paths().is_empty());
+       for path in offer.paths() {
+               assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
        }
+
+       let payment_id = PaymentId([1; 32]);
+       bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap();
+       expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
+
+       let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
+       alice.onion_messenger.handle_onion_message(&bob_id, &onion_message);
+
+       let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
+       let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
+               offer_id: offer.id(),
+               invoice_request: InvoiceRequestFields {
+                       payer_id: invoice_request.payer_id(),
+                       quantity: None,
+                       payer_note_truncated: None,
+               },
+       });
+       assert_ne!(invoice_request.payer_id(), bob_id);
+       assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(alice_id));
+
+       let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
+       bob.onion_messenger.handle_onion_message(&alice_id, &onion_message);
+
+       let invoice = extract_invoice(bob, &onion_message);
+       assert_ne!(invoice.signing_pubkey(), alice_id);
+       assert!(!invoice.payment_paths().is_empty());
+       for (_, path) in invoice.payment_paths() {
+               assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+       }
+
+       route_bolt12_payment(bob, &[alice], &invoice);
+       expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
+
+       claim_bolt12_payment(bob, &[alice], payment_context);
+       expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
 }
 
-/// Fails creating a refund when a blinded path cannot be created without exposing the node's id.
+/// Checks that a refund can be created using an unannounced node as a blinded path's introduction
+/// node. This is only preferred if there are no other options which may indicated either the refund
+/// is intended for the unannounced node or that the node is actually announced (e.g., an LSP) but
+/// the sender doesn't have a network graph.
 #[test]
-fn fails_creating_refund_without_blinded_paths() {
+fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
        let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
@@ -976,17 +1027,35 @@ fn fails_creating_refund_without_blinded_paths() {
 
        create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
 
+       let alice = &nodes[0];
+       let alice_id = alice.node.get_our_node_id();
+       let bob = &nodes[1];
+       let bob_id = bob.node.get_our_node_id();
+
        let absolute_expiry = Duration::from_secs(u64::MAX);
        let payment_id = PaymentId([1; 32]);
-
-       match nodes[0].node.create_refund_builder(
-               10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
-       ) {
-               Ok(_) => panic!("Expected error"),
-               Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
+       let refund = bob.node
+               .create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
+               .unwrap()
+               .build().unwrap();
+       assert_ne!(refund.payer_id(), bob_id);
+       assert!(!refund.paths().is_empty());
+       for path in refund.paths() {
+               assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
        }
+       expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
 
-       assert!(nodes[0].node.list_recent_payments().is_empty());
+       let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
+
+       let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
+
+       let invoice = extract_invoice(bob, &onion_message);
+       assert_eq!(invoice, expected_invoice);
+       assert_ne!(invoice.signing_pubkey(), alice_id);
+       assert!(!invoice.payment_paths().is_empty());
+       for (_, path) in invoice.payment_paths() {
+               assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
+       }
 }
 
 /// Fails creating or paying an offer when a blinded path cannot be created because no peers are
@@ -1165,8 +1234,7 @@ fn fails_sending_invoice_with_unsupported_chain_for_refund() {
        }
 }
 
-/// Fails creating an invoice request when a blinded reply path cannot be created without exposing
-/// the node's id.
+/// Fails creating an invoice request when a blinded reply path cannot be created.
 #[test]
 fn fails_creating_invoice_request_without_blinded_reply_path() {
        let chanmon_cfgs = create_chanmon_cfgs(6);
@@ -1183,7 +1251,7 @@ fn fails_creating_invoice_request_without_blinded_reply_path() {
        let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
 
        disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
-       disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
+       disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);
 
        let offer = alice.node
                .create_offer_builder(None).unwrap()
index 3ae128cb3bbe97f37016d0447fed25384ebf3dba..1915a4c5a14db61b4fe00c5ace6f36203f5791c2 100644 (file)
@@ -13,7 +13,8 @@ use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
 use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
 
-use crate::sign::{EntropySource, NodeSigner, Recipient};
+use crate::blinded_path::{IntroductionNode, NodeIdLookUp};
+use crate::blinded_path::payment::advance_path_by_one;
 use crate::events::{self, PaymentFailureReason};
 use crate::ln::types::{PaymentHash, PaymentPreimage, PaymentSecret};
 use crate::ln::channel_state::ChannelDetails;
@@ -22,6 +23,7 @@ use crate::ln::onion_utils;
 use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};
 use crate::offers::invoice::Bolt12Invoice;
 use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
+use crate::sign::{EntropySource, NodeSigner, Recipient};
 use crate::util::errors::APIError;
 use crate::util::logger::Logger;
 use crate::util::time::Time;
@@ -71,7 +73,7 @@ pub(crate) enum PendingOutboundPayment {
                keysend_preimage: Option<PaymentPreimage>,
                custom_tlvs: Vec<(u64, Vec<u8>)>,
                pending_amt_msat: u64,
-               /// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
+               /// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+.
                pending_fee_msat: Option<u64>,
                /// The total payment amount across all paths, used to verify that a retry is not overpaying.
                total_msat: u64,
@@ -775,10 +777,13 @@ impl OutboundPayments {
                }
        }
 
-       pub(super) fn send_payment_for_bolt12_invoice<R: Deref, ES: Deref, NS: Deref, IH, SP, L: Deref>(
+       pub(super) fn send_payment_for_bolt12_invoice<
+               R: Deref, ES: Deref, NS: Deref, NL: Deref, IH, SP, L: Deref
+       >(
                &self, invoice: &Bolt12Invoice, payment_id: PaymentId, router: &R,
                first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
-               best_block_height: u32, logger: &L,
+               node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32,
+               logger: &L,
                pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
                send_payment_along_path: SP,
        ) -> Result<(), Bolt12PaymentError>
@@ -786,6 +791,7 @@ impl OutboundPayments {
                R::Target: Router,
                ES::Target: EntropySource,
                NS::Target: NodeSigner,
+               NL::Target: NodeIdLookUp,
                L::Target: Logger,
                IH: Fn() -> InFlightHtlcs,
                SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
@@ -807,9 +813,30 @@ impl OutboundPayments {
                        hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
                };
 
-               let pay_params = PaymentParameters::from_bolt12_invoice(&invoice);
+               let mut payment_params = PaymentParameters::from_bolt12_invoice(&invoice);
+
+               // Advance any blinded path where the introduction node is our node.
+               if let Ok(our_node_id) = node_signer.get_node_id(Recipient::Node) {
+                       for (_, path) in payment_params.payee.blinded_route_hints_mut().iter_mut() {
+                               let introduction_node_id = match path.introduction_node {
+                                       IntroductionNode::NodeId(pubkey) => pubkey,
+                                       IntroductionNode::DirectedShortChannelId(direction, scid) => {
+                                               match node_id_lookup.next_node_id(scid) {
+                                                       Some(next_node_id) => *direction.select_pubkey(&our_node_id, &next_node_id),
+                                                       None => continue,
+                                               }
+                                       },
+                               };
+                               if introduction_node_id == our_node_id {
+                                       let _ = advance_path_by_one(path, node_signer, node_id_lookup, secp_ctx);
+                               }
+                       }
+               }
+
                let amount_msat = invoice.amount_msats();
-               let mut route_params = RouteParameters::from_payment_params_and_value(pay_params, amount_msat);
+               let mut route_params = RouteParameters::from_payment_params_and_value(
+                       payment_params, amount_msat
+               );
                if let Some(max_fee_msat) = max_total_routing_fee_msat {
                        route_params.max_total_routing_fee_msat = Some(max_fee_msat);
                }
@@ -1856,6 +1883,7 @@ mod tests {
 
        use core::time::Duration;
 
+       use crate::blinded_path::EmptyNodeIdLookUp;
        use crate::events::{Event, PathFailure, PaymentFailureReason};
        use crate::ln::types::PaymentHash;
        use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
@@ -2199,6 +2227,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2227,7 +2256,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Ok(()),
                );
@@ -2250,6 +2280,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2286,7 +2317,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Ok(()),
                );
@@ -2309,6 +2341,7 @@ mod tests {
                let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &logger));
                let scorer = RwLock::new(test_utils::TestScorer::new());
                let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
+               let secp_ctx = Secp256k1::new();
                let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
 
                let pending_events = Mutex::new(VecDeque::new());
@@ -2358,7 +2391,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Err(Bolt12PaymentError::UnexpectedInvoice),
                );
@@ -2375,7 +2409,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| Ok(())
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| Ok(())
                        ),
                        Ok(()),
                );
@@ -2385,7 +2420,8 @@ mod tests {
                assert_eq!(
                        outbound_payments.send_payment_for_bolt12_invoice(
                                &invoice, payment_id, &&router, vec![], || InFlightHtlcs::new(), &&keys_manager,
-                               &&keys_manager, 0, &&logger, &pending_events, |_| panic!()
+                               &&keys_manager, &EmptyNodeIdLookUp {}, &secp_ctx, 0, &&logger, &pending_events,
+                               |_| panic!()
                        ),
                        Err(Bolt12PaymentError::DuplicateInvoice),
                );
index dcfb6ed8de77768abb8d49d6de292d36344185f4..fcfdd5cb5a02f64e688ddd7cdb9b375029907226 100644 (file)
@@ -2053,22 +2053,28 @@ fn accept_underpaying_htlcs_config() {
 fn do_accept_underpaying_htlcs_config(num_mpp_parts: usize) {
        let chanmon_cfgs = create_chanmon_cfgs(3);
        let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let max_in_flight_percent = 10;
        let mut intercept_forwards_config = test_default_channel_config();
        intercept_forwards_config.accept_intercept_htlcs = true;
+       intercept_forwards_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = max_in_flight_percent;
        let mut underpay_config = test_default_channel_config();
        underpay_config.channel_config.accept_underpaying_htlcs = true;
+       underpay_config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = max_in_flight_percent;
        let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, Some(intercept_forwards_config), Some(underpay_config)]);
        let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
 
+       let amt_msat = 900_000;
+
        let mut chan_ids = Vec::new();
        for _ in 0..num_mpp_parts {
-               let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000, 0);
-               let channel_id = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, 2_000_000, 0).0.channel_id;
+               // We choose the channel size so that there can be at most one part pending on each channel.
+               let channel_size = amt_msat / 1000 / num_mpp_parts as u64 * 100 / max_in_flight_percent as u64 + 100;
+               let _ = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, channel_size, 0);
+               let channel_id = create_unannounced_chan_between_nodes_with_value(&nodes, 1, 2, channel_size, 0).0.channel_id;
                chan_ids.push(channel_id);
        }
 
        // Send the initial payment.
-       let amt_msat = 900_000;
        let skimmed_fee_msat = 20;
        let mut route_hints = Vec::new();
        for _ in 0..num_mpp_parts {
@@ -4098,7 +4104,7 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) {
 
        // Create a new channel between C and D as A will refuse to retry on the existing one because
        // it just failed.
-       let chan_id_cd_2 = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).2;
+       create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0);
 
        // Now retry the failed HTLC.
        nodes[0].node.process_pending_htlc_forwards();
@@ -4110,6 +4116,7 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) {
        expect_pending_htlcs_forwardable!(nodes[2]);
        check_added_monitors(&nodes[2], 1);
        let cs_forward = SendEvent::from_node(&nodes[2]);
+       let cd_channel_used = cs_forward.msgs[0].channel_id;
        nodes[3].node.handle_update_add_htlc(&nodes[2].node.get_our_node_id(), &cs_forward.msgs[0]);
        commitment_signed_dance!(nodes[3], nodes[2], cs_forward.commitment_msg, false, true);
 
@@ -4129,7 +4136,7 @@ fn do_test_payment_metadata_consistency(do_reload: bool, do_modify: bool) {
                nodes[2].node.handle_update_fail_htlc(&nodes[3].node.get_our_node_id(), &ds_fail.update_fail_htlcs[0]);
                commitment_signed_dance!(nodes[2], nodes[3], ds_fail.commitment_signed, false, true);
                expect_pending_htlcs_forwardable_conditions(nodes[2].node.get_and_clear_pending_events(),
-                       &[HTLCDestination::NextHopChannel { node_id: Some(nodes[3].node.get_our_node_id()), channel_id: chan_id_cd_2 }]);
+                       &[HTLCDestination::NextHopChannel { node_id: Some(nodes[3].node.get_our_node_id()), channel_id: cd_channel_used }]);
        } else {
                expect_pending_htlcs_forwardable!(nodes[3]);
                expect_payment_claimable!(nodes[3], payment_hash, payment_secret, amt_msat);
@@ -4294,3 +4301,94 @@ fn peel_payment_onion_custom_tlvs() {
                _ => panic!()
        }
 }
+
+#[test]
+fn test_non_strict_forwarding() {
+       let chanmon_cfgs = create_chanmon_cfgs(3);
+       let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
+       let mut config = test_default_channel_config();
+       config.channel_handshake_config.max_inbound_htlc_value_in_flight_percent_of_channel = 100;
+       let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[Some(config), Some(config), Some(config)]);
+       let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+
+       // Create a routing node with two outbound channels, each of which can forward 2 payments of
+       // the given value.
+       let payment_value = 1_500_000;
+       create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100_000, 0);
+       let (chan_update_1, _, channel_id_1, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 4_950, 0);
+       let (chan_update_2, _, channel_id_2, _) = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 5_000, 0);
+
+       // Create a route once.
+       let payment_params = PaymentParameters::from_node_id(nodes[2].node.get_our_node_id(), TEST_FINAL_CLTV)
+               .with_bolt11_features(nodes[2].node.bolt11_invoice_features()).unwrap();
+       let route_params = RouteParameters::from_payment_params_and_value(payment_params, payment_value);
+       let route = functional_test_utils::get_route(&nodes[0], &route_params).unwrap();
+
+       // Send 4 payments over the same route.
+       for i in 0..4 {
+               let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(payment_value), None);
+               nodes[0].node.send_payment_with_route(&route, payment_hash,
+                       RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
+               check_added_monitors!(nodes[0], 1);
+               let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+               assert_eq!(msg_events.len(), 1);
+               let mut send_event = SendEvent::from_event(msg_events.remove(0));
+               nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
+               commitment_signed_dance!(nodes[1], nodes[0], &send_event.commitment_msg, false);
+
+               expect_pending_htlcs_forwardable!(nodes[1]);
+               check_added_monitors!(nodes[1], 1);
+               msg_events = nodes[1].node.get_and_clear_pending_msg_events();
+               assert_eq!(msg_events.len(), 1);
+               send_event = SendEvent::from_event(msg_events.remove(0));
+               // The HTLC will be forwarded over the most appropriate channel with the corresponding peer,
+               // applying non-strict forwarding.
+               // The channel with the least amount of outbound liquidity will be used to maximize the
+               // probability of being able to successfully forward a subsequent HTLC.
+               assert_eq!(send_event.msgs[0].channel_id, if i < 2 {
+                       channel_id_1
+               } else {
+                       channel_id_2
+               });
+               nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &send_event.msgs[0]);
+               commitment_signed_dance!(nodes[2], nodes[1], &send_event.commitment_msg, false);
+
+               expect_pending_htlcs_forwardable!(nodes[2]);
+               let events = nodes[2].node.get_and_clear_pending_events();
+               assert_eq!(events.len(), 1);
+               assert!(matches!(events[0], Event::PaymentClaimable { .. }));
+
+               claim_payment_along_route(
+                       ClaimAlongRouteArgs::new(&nodes[0], &[&[&nodes[1], &nodes[2]]], payment_preimage)
+               );
+       }
+
+       // Send a 5th payment which will fail.
+       let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(payment_value), None);
+       nodes[0].node.send_payment_with_route(&route, payment_hash,
+               RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0)).unwrap();
+       check_added_monitors!(nodes[0], 1);
+       let mut msg_events = nodes[0].node.get_and_clear_pending_msg_events();
+       assert_eq!(msg_events.len(), 1);
+       let mut send_event = SendEvent::from_event(msg_events.remove(0));
+       nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &send_event.msgs[0]);
+       commitment_signed_dance!(nodes[1], nodes[0], &send_event.commitment_msg, false);
+
+       expect_pending_htlcs_forwardable!(nodes[1]);
+       check_added_monitors!(nodes[1], 1);
+       let routed_scid = route.paths[0].hops[1].short_channel_id;
+       let routed_channel_id = match routed_scid {
+               scid if scid == chan_update_1.contents.short_channel_id => channel_id_1,
+               scid if scid == chan_update_2.contents.short_channel_id => channel_id_2,
+               _ => panic!("Unexpected short channel id in route"),
+       };
+       // The failure to forward will refer to the channel given in the onion.
+       expect_pending_htlcs_forwardable_conditions(nodes[1].node.get_and_clear_pending_events(),
+               &[HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: routed_channel_id }]);
+
+       let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+       nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &updates.update_fail_htlcs[0]);
+       commitment_signed_dance!(nodes[0], nodes[1], updates.commitment_signed, false);
+       let events = nodes[0].node.get_and_clear_pending_events();
+       expect_payment_failed_conditions_event(events, payment_hash, false, PaymentFailedConditions::new().blamed_scid(routed_scid));
+}
index 08be1b2c5027d64bdf599faca92f0b2ed510ef5c..ed601c047c28a1edfbd1bb930a74a3c8ccf33441 100644 (file)
@@ -492,8 +492,9 @@ fn async_response_with_reply_path_fails() {
        let path_id = Some([2; 32]);
        let reply_path = BlindedPath::new_for_message(&[], bob.node_id, &*bob.entropy_source, &secp_ctx).unwrap();
 
-       // Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced.
-       // Therefore, the reply_path cannot be used for the response.
+       // Alice tries to asynchronously respond to Bob, but fails because the nodes are unannounced and
+       // disconnected. Thus, a reply path could no be created for the response.
+       disconnect_peers(alice, bob);
        let responder = Responder::new(reply_path, path_id);
        alice.custom_message_handler.expect_message_and_response(message.clone());
        let response_instruction = alice.custom_message_handler.handle_custom_message(message, Some(responder));
index 0fb72c52d2784a03973bfb3ac2bbf846fc3daba6..859c3f2b5b9c88fd6e7c42c23698d1402dcbee61 100644 (file)
@@ -489,7 +489,7 @@ where
        }
 
        fn create_blinded_paths_from_iter<
-               I: Iterator<Item = ForwardNode>,
+               I: ExactSizeIterator<Item = ForwardNode>,
                T: secp256k1::Signing + secp256k1::Verification
        >(
                &self, recipient: PublicKey, peers: I, secp_ctx: &Secp256k1<T>, compact_paths: bool
@@ -505,13 +505,20 @@ where
                let is_recipient_announced =
                        network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient));
 
+               let has_one_peer = peers.len() == 1;
                let mut peer_info = peers
-                       // Limit to peers with announced channels
+                       // Limit to peers with announced channels unless the recipient is unannounced.
                        .filter_map(|peer|
                                network_graph
                                        .node(&NodeId::from_pubkey(&peer.node_id))
-                                       .filter(|info| info.channels.len() >= MIN_PEER_CHANNELS)
+                                       .filter(|info|
+                                               !is_recipient_announced || info.channels.len() >= MIN_PEER_CHANNELS
+                                       )
                                        .map(|info| (peer, info.is_tor_only(), info.channels.len()))
+                                       // Allow messages directly with the only peer when unannounced.
+                                       .or_else(|| (!is_recipient_announced && has_one_peer)
+                                               .then(|| (peer, false, 0))
+                                       )
                        )
                        // Exclude Tor-only nodes when the recipient is announced.
                        .filter(|(_, is_tor_only, _)| !(*is_tor_only && is_recipient_announced))
index 9a88d913896778dfc3b70ee0d97179c56e43c806..28aaba0513fb45de1e9ba9b24d42b463bd548ba4 100644 (file)
@@ -100,16 +100,31 @@ impl<G: Deref<Target = NetworkGraph<L>> + Clone, L: Deref, ES: Deref, S: Deref,
                // recipient's node_id.
                const MIN_PEER_CHANNELS: usize = 3;
 
+               let has_one_peer = first_hops
+                       .first()
+                       .map(|details| details.counterparty.node_id)
+                       .map(|node_id| first_hops
+                               .iter()
+                               .skip(1)
+                               .all(|details| details.counterparty.node_id == node_id)
+                       )
+                       .unwrap_or(false);
+
                let network_graph = self.network_graph.deref().read_only();
+               let is_recipient_announced =
+                       network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient));
+
                let paths = first_hops.into_iter()
                        .filter(|details| details.counterparty.features.supports_route_blinding())
                        .filter(|details| amount_msats <= details.inbound_capacity_msat)
                        .filter(|details| amount_msats >= details.inbound_htlc_minimum_msat.unwrap_or(0))
                        .filter(|details| amount_msats <= details.inbound_htlc_maximum_msat.unwrap_or(u64::MAX))
+                       // Limit to peers with announced channels unless the recipient is unannounced.
                        .filter(|details| network_graph
                                        .node(&NodeId::from_pubkey(&details.counterparty.node_id))
-                                       .map(|node_info| node_info.channels.len() >= MIN_PEER_CHANNELS)
-                                       .unwrap_or(false)
+                                       .map(|node| !is_recipient_announced || node.channels.len() >= MIN_PEER_CHANNELS)
+                                       // Allow payments directly with the only peer when unannounced.
+                                       .unwrap_or(!is_recipient_announced && has_one_peer)
                        )
                        .filter_map(|details| {
                                let short_channel_id = match details.get_inbound_payment_scid() {
@@ -1031,6 +1046,13 @@ impl Payee {
                }
        }
 
+       pub(crate) fn blinded_route_hints_mut(&mut self) -> &mut [(BlindedPayInfo, BlindedPath)] {
+               match self {
+                       Self::Blinded { route_hints, .. } => &mut route_hints[..],
+                       Self::Clear { .. } => &mut []
+               }
+       }
+
        fn unblinded_route_hints(&self) -> &[RouteHint] {
                match self {
                        Self::Blinded { .. } => &[],
index 2009e4d0b08a9a22fd68941b8290bfabffe75203..884acc2c2eac1835ca07f6949afd172effe2e62e 100644 (file)
@@ -18,7 +18,7 @@ use crate::sign::ecdsa::EcdsaChannelSigner;
 #[allow(unused_imports)]
 use crate::prelude::*;
 
-use core::cmp;
+use core::{cmp, fmt};
 use crate::sync::{Mutex, Arc};
 #[cfg(test)] use crate::sync::MutexGuard;
 
@@ -71,9 +71,46 @@ pub struct TestChannelSigner {
        /// Channel state used for policy enforcement
        pub state: Arc<Mutex<EnforcementState>>,
        pub disable_revocation_policy_check: bool,
-       /// When `true` (the default), the signer will respond immediately with signatures. When `false`,
-       /// the signer will return an error indicating that it is unavailable.
-       pub available: Arc<Mutex<bool>>,
+       /// Set of signer operations that are disabled. If an operation is disabled,
+       /// the signer will return `Err` when the corresponding method is called.
+       pub disabled_signer_ops: Arc<Mutex<HashSet<SignerOp>>>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum SignerOp {
+       GetPerCommitmentPoint,
+       ReleaseCommitmentSecret,
+       ValidateHolderCommitment,
+       SignCounterpartyCommitment,
+       ValidateCounterpartyRevocation,
+       SignHolderCommitment,
+       SignJusticeRevokedOutput,
+       SignJusticeRevokedHtlc,
+       SignHolderHtlcTransaction,
+       SignCounterpartyHtlcTransaction,
+       SignClosingTransaction,
+       SignHolderAnchorInput,
+       SignChannelAnnouncementWithFundingKey,
+}
+
+impl fmt::Display for SignerOp {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               match self {
+                       SignerOp::GetPerCommitmentPoint => write!(f, "get_per_commitment_point"),
+                       SignerOp::ReleaseCommitmentSecret => write!(f, "release_commitment_secret"),
+                       SignerOp::ValidateHolderCommitment => write!(f, "validate_holder_commitment"),
+                       SignerOp::SignCounterpartyCommitment => write!(f, "sign_counterparty_commitment"),
+                       SignerOp::ValidateCounterpartyRevocation => write!(f, "validate_counterparty_revocation"),
+                       SignerOp::SignHolderCommitment => write!(f, "sign_holder_commitment"),
+                       SignerOp::SignJusticeRevokedOutput => write!(f, "sign_justice_revoked_output"),
+                       SignerOp::SignJusticeRevokedHtlc => write!(f, "sign_justice_revoked_htlc"),
+                       SignerOp::SignHolderHtlcTransaction => write!(f, "sign_holder_htlc_transaction"),
+                       SignerOp::SignCounterpartyHtlcTransaction => write!(f, "sign_counterparty_htlc_transaction"),
+                       SignerOp::SignClosingTransaction => write!(f, "sign_closing_transaction"),
+                       SignerOp::SignHolderAnchorInput => write!(f, "sign_holder_anchor_input"),
+                       SignerOp::SignChannelAnnouncementWithFundingKey => write!(f, "sign_channel_announcement_with_funding_key"),
+               }
+       }
 }
 
 impl PartialEq for TestChannelSigner {
@@ -90,7 +127,7 @@ impl TestChannelSigner {
                        inner,
                        state,
                        disable_revocation_policy_check: false,
-                       available: Arc::new(Mutex::new(true)),
+                       disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
                }
        }
 
@@ -104,7 +141,7 @@ impl TestChannelSigner {
                        inner,
                        state,
                        disable_revocation_policy_check,
-                       available: Arc::new(Mutex::new(true)),
+                       disabled_signer_ops: Arc::new(Mutex::new(new_hash_set())),
                }
        }
 
@@ -115,13 +152,16 @@ impl TestChannelSigner {
                self.state.lock().unwrap()
        }
 
-       /// Marks the signer's availability.
-       ///
-       /// When `true`, methods are forwarded to the underlying signer as normal. When `false`, some
-       /// methods will return `Err` indicating that the signer is unavailable. Intended to be used for
-       /// testing asynchronous signing.
-       pub fn set_available(&self, available: bool) {
-               *self.available.lock().unwrap() = available;
+       pub fn enable_op(&mut self, signer_op: SignerOp) {
+               self.disabled_signer_ops.lock().unwrap().remove(&signer_op);
+       }
+
+       pub fn disable_op(&mut self, signer_op: SignerOp) {
+               self.disabled_signer_ops.lock().unwrap().insert(signer_op);
+       }
+
+       fn is_signer_available(&self, signer_op: SignerOp) -> bool {
+               !self.disabled_signer_ops.lock().unwrap().contains(&signer_op)
        }
 }
 
@@ -149,7 +189,7 @@ impl ChannelSigner for TestChannelSigner {
        }
 
        fn validate_counterparty_revocation(&self, idx: u64, _secret: &SecretKey) -> Result<(), ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::ValidateCounterpartyRevocation) {
                        return Err(());
                }
                let mut state = self.state.lock().unwrap();
@@ -172,7 +212,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
                self.verify_counterparty_commitment_tx(commitment_tx, secp_ctx);
 
                {
-                       if !*self.available.lock().unwrap() {
+                       if !self.is_signer_available(SignerOp::SignCounterpartyCommitment) {
                                return Err(());
                        }
                        let mut state = self.state.lock().unwrap();
@@ -191,7 +231,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
        }
 
        fn sign_holder_commitment(&self, commitment_tx: &HolderCommitmentTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignHolderCommitment) {
                        return Err(());
                }
                let trusted_tx = self.verify_holder_commitment_tx(commitment_tx, secp_ctx);
@@ -212,14 +252,14 @@ impl EcdsaChannelSigner for TestChannelSigner {
        }
 
        fn sign_justice_revoked_output(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignJusticeRevokedOutput) {
                        return Err(());
                }
                Ok(EcdsaChannelSigner::sign_justice_revoked_output(&self.inner, justice_tx, input, amount, per_commitment_key, secp_ctx).unwrap())
        }
 
        fn sign_justice_revoked_htlc(&self, justice_tx: &Transaction, input: usize, amount: u64, per_commitment_key: &SecretKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignJusticeRevokedHtlc) {
                        return Err(());
                }
                Ok(EcdsaChannelSigner::sign_justice_revoked_htlc(&self.inner, justice_tx, input, amount, per_commitment_key, htlc, secp_ctx).unwrap())
@@ -229,7 +269,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
                &self, htlc_tx: &Transaction, input: usize, htlc_descriptor: &HTLCDescriptor,
                secp_ctx: &Secp256k1<secp256k1::All>
        ) -> Result<Signature, ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignHolderHtlcTransaction) {
                        return Err(());
                }
                let state = self.state.lock().unwrap();
@@ -265,7 +305,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
        }
 
        fn sign_counterparty_htlc_transaction(&self, htlc_tx: &Transaction, input: usize, amount: u64, per_commitment_point: &PublicKey, htlc: &HTLCOutputInCommitment, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignCounterpartyHtlcTransaction) {
                        return Err(());
                }
                Ok(EcdsaChannelSigner::sign_counterparty_htlc_transaction(&self.inner, htlc_tx, input, amount, per_commitment_point, htlc, secp_ctx).unwrap())
@@ -284,7 +324,7 @@ impl EcdsaChannelSigner for TestChannelSigner {
                // As long as our minimum dust limit is enforced and is greater than our anchor output
                // value, an anchor output can only have an index within [0, 1].
                assert!(anchor_tx.input[input].previous_output.vout == 0 || anchor_tx.input[input].previous_output.vout == 1);
-               if !*self.available.lock().unwrap() {
+               if !self.is_signer_available(SignerOp::SignHolderAnchorInput) {
                        return Err(());
                }
                EcdsaChannelSigner::sign_holder_anchor_input(&self.inner, anchor_tx, input, secp_ctx)
index 2d00844772aca60eb841b2eb5bde57f7dcae8556..4d17f8fd17ddcd9a919acb4a4abddd9aac673c17 100644 (file)
@@ -79,6 +79,8 @@ use std::time::{SystemTime, UNIX_EPOCH};
 use bitcoin::psbt::Psbt;
 use bitcoin::Sequence;
 
+use super::test_channel_signer::SignerOp;
+
 pub fn pubkey(byte: u8) -> PublicKey {
        let secp_ctx = Secp256k1::new();
        PublicKey::from_secret_key(&secp_ctx, &privkey(byte))
@@ -1222,6 +1224,7 @@ pub struct TestKeysInterface {
        enforcement_states: Mutex<HashMap<[u8;32], Arc<Mutex<EnforcementState>>>>,
        expectations: Mutex<Option<VecDeque<OnGetShutdownScriptpubkey>>>,
        pub unavailable_signers: Mutex<HashSet<[u8; 32]>>,
+       pub unavailable_signers_ops: Mutex<HashMap<[u8; 32], HashSet<SignerOp>>>,
 }
 
 impl EntropySource for TestKeysInterface {
@@ -1280,9 +1283,11 @@ impl SignerProvider for TestKeysInterface {
        fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> TestChannelSigner {
                let keys = self.backing.derive_channel_signer(channel_value_satoshis, channel_keys_id);
                let state = self.make_enforcement_state_cell(keys.commitment_seed);
-               let signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check);
-               if self.unavailable_signers.lock().unwrap().contains(&channel_keys_id) {
-                       signer.set_available(false);
+               let mut signer = TestChannelSigner::new_with_revoked(keys, state, self.disable_revocation_policy_check);
+               if let Some(ops) = self.unavailable_signers_ops.lock().unwrap().get(&channel_keys_id) {
+                       for &op in ops {
+                               signer.disable_op(op);
+                       }
                }
                signer
        }
@@ -1323,6 +1328,7 @@ impl TestKeysInterface {
                        enforcement_states: Mutex::new(new_hash_map()),
                        expectations: Mutex::new(None),
                        unavailable_signers: Mutex::new(new_hash_set()),
+                       unavailable_signers_ops: Mutex::new(new_hash_map()),
                }
        }
 
index cb3d02ec5a316b0d6524fa716fa03016fa0eadd8..500330020b323822b268e2f105cff734a06a0cd5 100644 (file)
@@ -1,4 +1,3 @@
-./bench/benches/bench.rs
 ./lightning-background-processor/src/lib.rs
 ./lightning-block-sync/src/convert.rs
 ./lightning-block-sync/src/gossip.rs
@@ -24,9 +23,6 @@
 ./lightning-persister/src/lib.rs
 ./lightning-persister/src/test_utils.rs
 ./lightning-persister/src/utils.rs
-./lightning-rapid-gossip-sync/src/error.rs
-./lightning-rapid-gossip-sync/src/lib.rs
-./lightning-rapid-gossip-sync/src/processing.rs
 ./lightning/src/blinded_path/message.rs
 ./lightning/src/blinded_path/mod.rs
 ./lightning/src/blinded_path/payment.rs