Merge pull request #3101 from tnull/2024-06-fix-tx-sync
[rust-lightning] / lightning / src / ln / channelmanager.rs
index 921ea03b8cae781df32165ebfaaae6919288433b..992fd3c6f02d258c82a570e40567ddc2049b06c3 100644 (file)
@@ -46,7 +46,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
 use crate::ln::inbound_payment;
 use crate::ln::types::{ChannelId, PaymentHash, PaymentPreimage, PaymentSecret};
 use crate::ln::channel::{self, Channel, ChannelPhase, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, WithChannelContext};
-use crate::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState, CounterpartyForwardingInfo};
+use crate::ln::channel_state::ChannelDetails;
 use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 #[cfg(any(feature = "_test_utils", test))]
 use crate::ln::features::Bolt11InvoiceFeatures;
@@ -1554,8 +1554,9 @@ where
 /// #
 /// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
 /// # let channel_manager = channel_manager.get_cm();
+/// # let absolute_expiry = None;
 /// let offer = channel_manager
-///     .create_offer_builder()?
+///     .create_offer_builder(absolute_expiry)?
 /// # ;
 /// # // Needed for compiling for c_bindings
 /// # let builder: lightning::offers::offer::OfferBuilder<_, _> = offer.into();
@@ -2287,6 +2288,19 @@ const MAX_UNFUNDED_CHANNEL_PEERS: usize = 50;
 /// many peers we reject new (inbound) connections.
 const MAX_NO_CHANNEL_PEERS: usize = 250;
 
+/// The maximum expiration from the current time where an [`Offer`] or [`Refund`] is considered
+/// short-lived, while anything with a greater expiration is considered long-lived.
+///
+/// Using [`ChannelManager::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
+/// will included a [`BlindedPath`] created using:
+/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
+/// - [`MessageRouter::create_blinded_paths`] when long-lived.
+///
+/// Using compact [`BlindedPath`]s may provide better privacy as the [`MessageRouter`] could select
+/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
+/// become invalid over time as channels are closed. Thus, they are only suitable for short-term use.
+pub const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
+
 /// Used by [`ChannelManager::list_recent_payments`] to express the status of recent payments.
 /// These include payments that have yet to find a successful path, or have unresolved HTLCs.
 #[derive(Debug, PartialEq)]
@@ -8240,16 +8254,15 @@ where
 
 macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
        /// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
-       /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer will
-       /// not have an expiration unless otherwise set on the builder.
+       /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer's
+       /// expiration will be `absolute_expiry` if `Some`, otherwise it will not expire.
        ///
        /// # Privacy
        ///
-       /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the offer.
-       /// However, if one is not found, uses a one-hop [`BlindedPath`] with
-       /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
-       /// the node must be announced, otherwise, there is no way to find a path to the introduction in
-       /// order to send the [`InvoiceRequest`].
+       /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the offer based on the given
+       /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
+       /// privacy implications as well as those of the parameterized [`Router`], which implements
+       /// [`MessageRouter`].
        ///
        /// Also, uses a derived signing pubkey in the offer for recipient privacy.
        ///
@@ -8264,19 +8277,27 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
        ///
        /// [`Offer`]: crate::offers::offer::Offer
        /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
-       pub fn create_offer_builder(&$self) -> Result<$builder, Bolt12SemanticError> {
+       pub fn create_offer_builder(
+               &$self, absolute_expiry: Option<Duration>
+       ) -> Result<$builder, Bolt12SemanticError> {
                let node_id = $self.get_our_node_id();
                let expanded_key = &$self.inbound_payment_key;
                let entropy = &*$self.entropy_source;
                let secp_ctx = &$self.secp_ctx;
 
-               let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
+               let path = $self.create_blinded_path_using_absolute_expiry(absolute_expiry)
+                       .map_err(|_| Bolt12SemanticError::MissingPaths)?;
                let builder = OfferBuilder::deriving_signing_pubkey(
                        node_id, expanded_key, entropy, secp_ctx
                )
                        .chain_hash($self.chain_hash)
                        .path(path);
 
+               let builder = match absolute_expiry {
+                       None => builder,
+                       Some(absolute_expiry) => builder.absolute_expiry(absolute_expiry),
+               };
+
                Ok(builder.into())
        }
 } }
@@ -8304,11 +8325,10 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
        ///
        /// # Privacy
        ///
-       /// Uses [`MessageRouter::create_blinded_paths`] to construct a [`BlindedPath`] for the refund.
-       /// However, if one is not found, uses a one-hop [`BlindedPath`] with
-       /// [`ChannelManager::get_our_node_id`] as the introduction node instead. In the latter case,
-       /// the node must be announced, otherwise, there is no way to find a path to the introduction in
-       /// order to send the [`Bolt12Invoice`].
+       /// Uses [`MessageRouter`] to construct a [`BlindedPath`] for the refund based on the given
+       /// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
+       /// privacy implications as well as those of the parameterized [`Router`], which implements
+       /// [`MessageRouter`].
        ///
        /// Also, uses a derived payer id in the refund for payer privacy.
        ///
@@ -8337,7 +8357,8 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
                let entropy = &*$self.entropy_source;
                let secp_ctx = &$self.secp_ctx;
 
-               let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
+               let path = $self.create_blinded_path_using_absolute_expiry(Some(absolute_expiry))
+                       .map_err(|_| Bolt12SemanticError::MissingPaths)?;
                let builder = RefundBuilder::deriving_payer_id(
                        node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
                )?
@@ -8406,10 +8427,9 @@ where
        ///
        /// # Privacy
        ///
-       /// Uses a one-hop [`BlindedPath`] for the reply path with [`ChannelManager::get_our_node_id`]
-       /// as the introduction node and a derived payer id for payer privacy. As such, currently, the
-       /// node must be announced. Otherwise, there is no way to find a path to the introduction node
-       /// in order to send the [`Bolt12Invoice`].
+       /// For payer privacy, uses a derived payer id and uses [`MessageRouter::create_blinded_paths`]
+       /// to construct a [`BlindedPath`] for the reply path. For further privacy implications, see the
+       /// docs of the parameterized [`Router`], which implements [`MessageRouter`].
        ///
        /// # Limitations
        ///
@@ -8686,6 +8706,38 @@ where
                inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
        }
 
+       /// Creates a blinded path by delegating to [`MessageRouter`] based on the path's intended
+       /// lifetime.
+       ///
+       /// Whether or not the path is compact depends on whether the path is short-lived or long-lived,
+       /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See
+       /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`].
+       fn create_blinded_path_using_absolute_expiry(
+               &self, absolute_expiry: Option<Duration>
+       ) -> Result<BlindedPath, ()> {
+               let now = self.duration_since_epoch();
+               let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY);
+
+               if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry {
+                       self.create_compact_blinded_path()
+               } else {
+                       self.create_blinded_path()
+               }
+       }
+
+       pub(super) fn duration_since_epoch(&self) -> Duration {
+               #[cfg(not(feature = "std"))]
+               let now = Duration::from_secs(
+                       self.highest_seen_timestamp.load(Ordering::Acquire) as u64
+               );
+               #[cfg(feature = "std")]
+               let now = std::time::SystemTime::now()
+                       .duration_since(std::time::SystemTime::UNIX_EPOCH)
+                       .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
+
+               now
+       }
+
        /// Creates a blinded path by delegating to [`MessageRouter::create_blinded_paths`].
        ///
        /// Errors if the `MessageRouter` errors or returns an empty `Vec`.
@@ -8696,6 +8748,27 @@ where
                let peers = self.per_peer_state.read().unwrap()
                        .iter()
                        .map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
+                       .filter(|(_, peer)| peer.is_connected)
+                       .filter(|(_, peer)| peer.latest_features.supports_onion_messages())
+                       .map(|(node_id, _)| *node_id)
+                       .collect::<Vec<_>>();
+
+               self.router
+                       .create_blinded_paths(recipient, peers, secp_ctx)
+                       .and_then(|paths| paths.into_iter().next().ok_or(()))
+       }
+
+       /// Creates a blinded path by delegating to [`MessageRouter::create_compact_blinded_paths`].
+       ///
+       /// Errors if the `MessageRouter` errors or returns an empty `Vec`.
+       fn create_compact_blinded_path(&self) -> Result<BlindedPath, ()> {
+               let recipient = self.get_our_node_id();
+               let secp_ctx = &self.secp_ctx;
+
+               let peers = self.per_peer_state.read().unwrap()
+                       .iter()
+                       .map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
+                       .filter(|(_, peer)| peer.is_connected)
                        .filter(|(_, peer)| peer.latest_features.supports_onion_messages())
                        .map(|(node_id, peer)| ForwardNode {
                                node_id: *node_id,
@@ -8708,7 +8781,7 @@ where
                        .collect::<Vec<_>>();
 
                self.router
-                       .create_blinded_paths(recipient, peers, secp_ctx)
+                       .create_compact_blinded_paths(recipient, peers, secp_ctx)
                        .and_then(|paths| paths.into_iter().next().ok_or(()))
        }
 
@@ -10274,140 +10347,6 @@ pub fn provided_init_features(config: &UserConfig) -> InitFeatures {
 const SERIALIZATION_VERSION: u8 = 1;
 const MIN_SERIALIZATION_VERSION: u8 = 1;
 
-impl_writeable_tlv_based!(CounterpartyForwardingInfo, {
-       (2, fee_base_msat, required),
-       (4, fee_proportional_millionths, required),
-       (6, cltv_expiry_delta, required),
-});
-
-impl_writeable_tlv_based!(ChannelCounterparty, {
-       (2, node_id, required),
-       (4, features, required),
-       (6, unspendable_punishment_reserve, required),
-       (8, forwarding_info, option),
-       (9, outbound_htlc_minimum_msat, option),
-       (11, outbound_htlc_maximum_msat, option),
-});
-
-impl Writeable for ChannelDetails {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
-               // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
-               // versions prior to 0.0.113, the u128 is serialized as two separate u64 values.
-               let user_channel_id_low = self.user_channel_id as u64;
-               let user_channel_id_high_opt = Some((self.user_channel_id >> 64) as u64);
-               write_tlv_fields!(writer, {
-                       (1, self.inbound_scid_alias, option),
-                       (2, self.channel_id, required),
-                       (3, self.channel_type, option),
-                       (4, self.counterparty, required),
-                       (5, self.outbound_scid_alias, option),
-                       (6, self.funding_txo, option),
-                       (7, self.config, option),
-                       (8, self.short_channel_id, option),
-                       (9, self.confirmations, option),
-                       (10, self.channel_value_satoshis, required),
-                       (12, self.unspendable_punishment_reserve, option),
-                       (14, user_channel_id_low, required),
-                       (16, self.balance_msat, required),
-                       (18, self.outbound_capacity_msat, required),
-                       (19, self.next_outbound_htlc_limit_msat, required),
-                       (20, self.inbound_capacity_msat, required),
-                       (21, self.next_outbound_htlc_minimum_msat, required),
-                       (22, self.confirmations_required, option),
-                       (24, self.force_close_spend_delay, option),
-                       (26, self.is_outbound, required),
-                       (28, self.is_channel_ready, required),
-                       (30, self.is_usable, required),
-                       (32, self.is_public, required),
-                       (33, self.inbound_htlc_minimum_msat, option),
-                       (35, self.inbound_htlc_maximum_msat, option),
-                       (37, user_channel_id_high_opt, option),
-                       (39, self.feerate_sat_per_1000_weight, option),
-                       (41, self.channel_shutdown_state, option),
-                       (43, self.pending_inbound_htlcs, optional_vec),
-                       (45, self.pending_outbound_htlcs, optional_vec),
-               });
-               Ok(())
-       }
-}
-
-impl Readable for ChannelDetails {
-       fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
-               _init_and_read_len_prefixed_tlv_fields!(reader, {
-                       (1, inbound_scid_alias, option),
-                       (2, channel_id, required),
-                       (3, channel_type, option),
-                       (4, counterparty, required),
-                       (5, outbound_scid_alias, option),
-                       (6, funding_txo, option),
-                       (7, config, option),
-                       (8, short_channel_id, option),
-                       (9, confirmations, option),
-                       (10, channel_value_satoshis, required),
-                       (12, unspendable_punishment_reserve, option),
-                       (14, user_channel_id_low, required),
-                       (16, balance_msat, required),
-                       (18, outbound_capacity_msat, required),
-                       // Note that by the time we get past the required read above, outbound_capacity_msat will be
-                       // filled in, so we can safely unwrap it here.
-                       (19, next_outbound_htlc_limit_msat, (default_value, outbound_capacity_msat.0.unwrap() as u64)),
-                       (20, inbound_capacity_msat, required),
-                       (21, next_outbound_htlc_minimum_msat, (default_value, 0)),
-                       (22, confirmations_required, option),
-                       (24, force_close_spend_delay, option),
-                       (26, is_outbound, required),
-                       (28, is_channel_ready, required),
-                       (30, is_usable, required),
-                       (32, is_public, required),
-                       (33, inbound_htlc_minimum_msat, option),
-                       (35, inbound_htlc_maximum_msat, option),
-                       (37, user_channel_id_high_opt, option),
-                       (39, feerate_sat_per_1000_weight, option),
-                       (41, channel_shutdown_state, option),
-                       (43, pending_inbound_htlcs, optional_vec),
-                       (45, pending_outbound_htlcs, optional_vec),
-               });
-
-               // `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
-               // versions prior to 0.0.113, the u128 is serialized as two separate u64 values.
-               let user_channel_id_low: u64 = user_channel_id_low.0.unwrap();
-               let user_channel_id = user_channel_id_low as u128 +
-                       ((user_channel_id_high_opt.unwrap_or(0 as u64) as u128) << 64);
-
-               Ok(Self {
-                       inbound_scid_alias,
-                       channel_id: channel_id.0.unwrap(),
-                       channel_type,
-                       counterparty: counterparty.0.unwrap(),
-                       outbound_scid_alias,
-                       funding_txo,
-                       config,
-                       short_channel_id,
-                       channel_value_satoshis: channel_value_satoshis.0.unwrap(),
-                       unspendable_punishment_reserve,
-                       user_channel_id,
-                       balance_msat: balance_msat.0.unwrap(),
-                       outbound_capacity_msat: outbound_capacity_msat.0.unwrap(),
-                       next_outbound_htlc_limit_msat: next_outbound_htlc_limit_msat.0.unwrap(),
-                       next_outbound_htlc_minimum_msat: next_outbound_htlc_minimum_msat.0.unwrap(),
-                       inbound_capacity_msat: inbound_capacity_msat.0.unwrap(),
-                       confirmations_required,
-                       confirmations,
-                       force_close_spend_delay,
-                       is_outbound: is_outbound.0.unwrap(),
-                       is_channel_ready: is_channel_ready.0.unwrap(),
-                       is_usable: is_usable.0.unwrap(),
-                       is_public: is_public.0.unwrap(),
-                       inbound_htlc_minimum_msat,
-                       inbound_htlc_maximum_msat,
-                       feerate_sat_per_1000_weight,
-                       channel_shutdown_state,
-                       pending_inbound_htlcs: pending_inbound_htlcs.unwrap_or(Vec::new()),
-                       pending_outbound_htlcs: pending_outbound_htlcs.unwrap_or(Vec::new()),
-               })
-       }
-}
-
 impl_writeable_tlv_based!(PhantomRouteHints, {
        (2, channels, required_vec),
        (4, phantom_scid, required),
@@ -11042,14 +10981,6 @@ impl Readable for VecDeque<(Event, Option<EventCompletionAction>)> {
        }
 }
 
-impl_writeable_tlv_based_enum!(ChannelShutdownState,
-       (0, NotShuttingDown) => {},
-       (2, ShutdownInitiated) => {},
-       (4, ResolvingHTLCs) => {},
-       (6, NegotiatingClosingFee) => {},
-       (8, ShutdownComplete) => {}, ;
-);
-
 /// Arguments for the creation of a ChannelManager that are not deserialized.
 ///
 /// At a high-level, the process for deserializing a ChannelManager and resuming normal operation