Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Retry InvoiceRequest Flow #3010

Merged
merged 4 commits into from
Sep 12, 2024

Conversation

shaavan
Copy link
Contributor

@shaavan shaavan commented Apr 22, 2024

resolves #2836

Description:

  • Add functionality to handle retrying the sending of invoice_request messages on new reply_paths that are still awaiting invoices.

Changes:

  1. Introduced invoice_request as an optional field in the PendingOutboundPayments::AwaitingInvoice variant to accommodate instances without invoice requests.
  2. Refactored logic from pay_for_offer to create invoice request messages into a separate function for reuse with retry message flow.
  3. Implemented the retry_tick_occurred function in ChannelManager to handle generating invoice request messages for AwaitingInvoice payments and enqueueing them.
  4. Added retry_tick_occurred to ln_background_processor with a timer duration of 5 seconds for timely retries without overwhelming the system with too many onion messages.

@shaavan
Copy link
Contributor Author

shaavan commented Apr 26, 2024

Updated from pr3010.01 to pr3010.02 (diff):

Changes:

  1. Introduce Readable impl for InvoiceRequest
  2. Restructure commits.

@shaavan
Copy link
Contributor Author

shaavan commented Apr 27, 2024

Updated from pr3010.02 to pr3010.03 (diff):

Updates:

  1. Rebase on main, to resolve merge conflicts.
  2. Fix ci

@codecov-commenter
Copy link

codecov-commenter commented Apr 27, 2024

Codecov Report

Attention: Patch coverage is 95.09202% with 8 lines in your changes missing coverage. Please review.

Project coverage is 89.64%. Comparing base (db905e8) to head (b1cd887).
Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/ln/channelmanager.rs 87.17% 5 Missing ⚠️
lightning/src/offers/invoice_request.rs 50.00% 0 Missing and 2 partials ⚠️
lightning/src/ln/outbound_payment.rs 98.07% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3010      +/-   ##
==========================================
- Coverage   89.64%   89.64%   -0.01%     
==========================================
  Files         126      126              
  Lines      102251   102383     +132     
  Branches   102251   102383     +132     
==========================================
+ Hits        91666    91781     +115     
- Misses       7863     7874      +11     
- Partials     2722     2728       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@shaavan
Copy link
Contributor Author

shaavan commented Apr 29, 2024

Updated from pr3010.03 to pr3010.04 (diff):

Changes:

  1. Introduce retry_tick_occurred test.

@shaavan shaavan changed the title Introduce Retry Invoice Flow Introduce Retry InvoiceRequest Flow Apr 29, 2024
@shaavan
Copy link
Contributor Author

shaavan commented May 3, 2024

Updated from pr3010.04 to pr3010.05 (diff):

Addressed @TheBlueMatt comments

Updates:

  1. Removed the secondary timer in ln_background_processor.
  2. Moved the retry_tick_occurred to a private function, and renamed it to retry_invoice_request_messages.
  3. Decrease the FRESHNESS_TIMER duration, while introducing a call counter within timer_tick_occurred. This is done so that retry_invoice_request_messages can be called faster than the rest of the code without introducing a secondary timer.
  4. Update the test appropriately.

@shaavan
Copy link
Contributor Author

shaavan commented May 3, 2024

Updated from pr3010.05 to pr3010.06 (diff):

Update:

  1. Rebase on main.
  2. To keep the code consistent with the main, now the create_invoice_reqeust_message, and retry_invoice_request_messages functions return Result<(), Bolt12SemanticError>

@shaavan
Copy link
Contributor Author

shaavan commented May 3, 2024

Updated from pr3010.06 to pr3010.07 (diff):

Update:

  1. Replaced using unsafe with using internal Mutex variable for tracking call counts.

@shaavan
Copy link
Contributor Author

shaavan commented May 13, 2024

Updated from pr3010.07 to pr3010.08 (diff):

Changes:

  1. Rebase on main, to solve merge conflicts.

@TheBlueMatt
Copy link
Collaborator

TheBlueMatt commented May 13, 2024

I don't buy that we need a new counter. There's a lot of things that hang on the timer rate, but this is a great opportunity to redefine the constants in seconds and multiply out a rate. Looking at all the things we do in the timer tick, as far as I can tell the only one that doesn't have a counter and a limit constant already is timer_check_closing_negotiation_process, and it should be easy to add there.

@shaavan
Copy link
Contributor Author

shaavan commented May 14, 2024

Hi Matt!
Thanks a lot for the suggestion!

I think this will definitely be a more maintainable way to handle this change than introducing a counter!
Worked out your suggestion in a separate PR since they were quite different from this one: #3065
Let me know if the approach seems sound!

Thanks a lot!

@shaavan
Copy link
Contributor Author

shaavan commented Jun 10, 2024

Updated from pr3010.08 to pr3010.09 (diff):
Addressed @TheBlueMatt's comment

Update:

  1. Rebase on main
  2. Introduced a new approach for retrying invoice request messages.

Details:

  1. This approach triggers InvoiceRequest retries when any ChannelMessageHandler's handler is invoked by any message from any peer.
  2. It ensures that if an InvoiceRequest message fails to send on the first attempt due to network disconnection, it will retry as soon as we are back online and receive messages from our peer.
  3. It guarantees that we only retry once for a given PendingOutboundPayment.
  4. This approach allows retries independent of a sub-minute timer.

lightning/src/ln/msgs.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
@shaavan
Copy link
Contributor Author

shaavan commented Jun 12, 2024

Updated from pr3010.09 to pr3010.10 (diff):
Addressed @TheBlueMatt comments

Changes:

  1. Update function name from retry_invoice_requests -> handle_message_received, so that it's more explicit about its calling behavior than specific functionality.
  2. Move the function call to do_handle_message_without_peer_lock so that it can be triggered when any message from any peer for any handler is received.
  3. Updated the code to generate awaiting_invoice_flag from pending_outbound_payments instead of serialising it.

@shaavan
Copy link
Contributor Author

shaavan commented Jun 20, 2024

Updated from pr3010.10 to pr3010.11 (diff):

Changes:

  1. Rebase on main, to resolve merge conflicts.

@shaavan
Copy link
Contributor Author

shaavan commented Jun 20, 2024

@TheBlueMatt
A gentle ping! :)

@jkczyz jkczyz self-requested a review June 20, 2024 15:45
lightning/src/ln/msgs.rs Outdated Show resolved Hide resolved
lightning/src/ln/peer_handler.rs Outdated Show resolved Hide resolved
lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
@shaavan
Copy link
Contributor Author

shaavan commented Jun 27, 2024

Updated from pr3010.11 to pr3010.12 (diff):
Addressed @TheBlueMatt comments

Changes:

  1. Updated the handle_message_received documentation to be more generic, removing references to BOLT12.
  2. Removed the return Result type for handle_message_received as the result was unused in the codebase.
  3. Changed the TLV number of invoice_request to odd so that downgrade support is maintained.

lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
@shaavan
Copy link
Contributor Author

shaavan commented Aug 20, 2024

Updated from pr3010.22 to pr3010.23 (diff):

Changes:

  1. Rebase on main to resolve merge conflicts.
  2. Squash fixup commit
  3. No changes to the approach in this version.
Range-Diff:
1:  115fab41 ! 1:  8abd02fd Add InvoiceRequest and Context Fields in AwaitingInvoice
    @@ Metadata
     Author: shaavan <[email protected]>
     
      ## Commit message ##
    -    Add InvoiceRequest and Context Fields in AwaitingInvoice
    +    Add InvoiceRequest and Nonce Fields in AwaitingInvoice
     
    -    - Introduced `InvoiceRequest` and `context` fields in the `AwaitingInvoice`
    +    - Introduced `InvoiceRequest` and `nonce` fields in the `AwaitingInvoice`
           to enable recreation of the `InvoiceRequest` message for retries if the
           corresponding invoice is not received in time.
         - Added `awaiting_invoice` flag to track pending outbound payments with
    @@ lightning/src/ln/channelmanager.rs: where
     @@ lightning/src/ln/channelmanager.rs: macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
      
      		let nonce = Nonce::from_entropy_source(entropy);
    - 		let context = OffersContext::OutboundPayment { payment_id, nonce };
    + 		let context = OffersContext::OutboundPayment { payment_id, nonce, hmac: None };
     -		let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry))
     +		let path = $self.create_blinded_paths_using_absolute_expiry(context.clone(), Some(absolute_expiry))
      			.and_then(|paths| paths.into_iter().next().ok_or(()))
    @@ lightning/src/ln/channelmanager.rs: macro_rules! create_refund_builder { ($self:
      		$self.pending_outbound_payments
      			.add_new_awaiting_invoice(
     -				payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
    -+				payment_id, expiration, retry_strategy, max_total_routing_fee_msat, None, context
    ++				payment_id, expiration, retry_strategy, max_total_routing_fee_msat, None, nonce
      			)
      			.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
      
    -@@ lightning/src/ln/channelmanager.rs: where
    - 		let invoice_request = builder.build_and_sign()?;
    - 
    - 		let context = OffersContext::OutboundPayment { payment_id, nonce };
    --		let reply_paths = self.create_blinded_paths(context)
    -+		let reply_paths = self.create_blinded_paths(context.clone())
    - 			.map_err(|_| Bolt12SemanticError::MissingPaths)?;
    - 
    - 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
     @@ lightning/src/ln/channelmanager.rs: where
      		let expiration = StaleExpiration::TimerTicks(1);
      		self.pending_outbound_payments
      			.add_new_awaiting_invoice(
     -				payment_id, expiration, retry_strategy, max_total_routing_fee_msat
     +				payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
    -+				Some(invoice_request.clone()), context,
    ++				Some(invoice_request.clone()), nonce,
      			)
      			.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
      
    @@ lightning/src/ln/outbound_payment.rs: use bitcoin::hashes::Hash;
      
     +use crate::blinded_path::message::OffersContext;
      use crate::blinded_path::{IntroductionNode, NodeIdLookUp};
    - use crate::blinded_path::payment::advance_path_by_one;
      use crate::events::{self, PaymentFailureReason};
    -@@ lightning/src/ln/outbound_payment.rs: use crate::ln::channelmanager::{EventCompletionAction, HTLCSource, PaymentId};
    + use crate::ln::types::{PaymentHash, PaymentPreimage, PaymentSecret};
    +@@ lightning/src/ln/outbound_payment.rs: use crate::ln::features::Bolt12InvoiceFeatures;
      use crate::ln::onion_utils;
      use crate::ln::onion_utils::{DecodedOnionFailure, HTLCFailReason};
      use crate::offers::invoice::Bolt12Invoice;
     +use crate::offers::invoice_request::InvoiceRequest;
    ++use crate::offers::nonce::Nonce;
      use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteParameters, Router};
      use crate::sign::{EntropySource, NodeSigner, Recipient};
      use crate::util::errors::APIError;
    @@ lightning/src/ln/outbound_payment.rs: pub(crate) enum PendingOutboundPayment {
      		retry_strategy: Retry,
      		max_total_routing_fee_msat: Option<u64>,
     +		invoice_request: Option<InvoiceRequest>,
    -+		context: OffersContext,
    ++		nonce: Option<Nonce>,
      	},
      	InvoiceReceived {
      		payment_hash: PaymentHash,
    @@ lightning/src/ln/outbound_payment.rs: impl OutboundPayments {
      		&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry,
     -		max_total_routing_fee_msat: Option<u64>
     +		max_total_routing_fee_msat: Option<u64>, invoice_request: Option<InvoiceRequest>,
    -+		context: OffersContext,
    ++		nonce: Nonce,
      	) -> Result<(), ()> {
      		let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
      		match pending_outbounds.entry(payment_id) {
    @@ lightning/src/ln/outbound_payment.rs: impl OutboundPayments {
      					retry_strategy,
      					max_total_routing_fee_msat,
     +					invoice_request,
    -+					context,
    ++					nonce: Some(nonce),
      				});
     +				self.awaiting_invoice.store(true, Ordering::Release);
      
    @@ lightning/src/ln/outbound_payment.rs: impl OutboundPayments {
     +		}
     +
     +		let mut pending_outbound_payments = self.pending_outbound_payments.lock().unwrap();
    -+		let invoice_requests = pending_outbound_payments.iter_mut()
    -+			.filter_map(|(_, payment)| match payment {
    -+				PendingOutboundPayment::AwaitingInvoice { invoice_request, context, ..} => {
    -+					invoice_request.take().map(|req| (context.clone(), req))
    ++		let invoice_requests = pending_outbound_payments
    ++			.iter_mut()
    ++			.filter_map(|(payment_id, payment)| {
    ++				if let PendingOutboundPayment::AwaitingInvoice {
    ++					invoice_request, nonce: Some(nonce), ..
    ++				} = payment {
    ++					let context = OffersContext::OutboundPayment {
    ++						payment_id: *payment_id,
    ++						nonce: *nonce,
    ++						// TODO: hmac to be incorporated.
    ++						hmac: None,
    ++					};
    ++					invoice_request.take().map(|req| (context, req))
    ++				} else {
    ++					None
     +				}
    -+				_ => None,
     +			})
     +			.collect();
     +
    @@ lightning/src/ln/outbound_payment.rs: impl_writeable_tlv_based_enum_upgradable!(
      		(2, retry_strategy, required),
      		(4, max_total_routing_fee_msat, option),
     +		(5, invoice_request, option),
    -+		(6, context, required),
    ++		(7, nonce, option),
      	},
      	(7, InvoiceReceived) => {
      		(0, payment_hash, required),
     @@ lightning/src/ln/outbound_payment.rs: mod tests {
    - 
    - 	use core::time::Duration;
    - 
    -+	use crate::blinded_path::message::OffersContext;
    - 	use crate::blinded_path::EmptyNodeIdLookUp;
    - 	use crate::events::{Event, PathFailure, PaymentFailureReason};
    - 	use crate::ln::types::PaymentHash;
    -@@ lightning/src/ln/outbound_payment.rs: mod tests {
    + 	use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
    + 	#[cfg(feature = "std")]
    + 	use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
    ++	use crate::offers::nonce::Nonce;
    + 	use crate::offers::offer::OfferBuilder;
    + 	use crate::offers::test_utils::*;
    + 	use crate::routing::gossip::NetworkGraph;
      	use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
      	use crate::sync::{Arc, Mutex, RwLock};
      	use crate::util::errors::APIError;
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_err()
      		);
      	}
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_err()
      		);
      	}
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), None
    -+				payment_id, expiration, Retry::Attempts(0), None, None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), None, None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      			outbound_payments.add_new_awaiting_invoice(
      				payment_id, expiration, Retry::Attempts(0),
     -				Some(invoice.amount_msats() / 100 + 50_000)
    -+				Some(invoice.amount_msats() / 100 + 50_000), None, OffersContext::Unknown {}
    ++				Some(invoice.amount_msats() / 100 + 50_000), None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
    @@ lightning/src/ln/outbound_payment.rs: mod tests {
      		assert!(
      			outbound_payments.add_new_awaiting_invoice(
     -				payment_id, expiration, Retry::Attempts(0), Some(1234)
    -+				payment_id, expiration, Retry::Attempts(0), Some(1234), None, OffersContext::Unknown {}
    ++				payment_id, expiration, Retry::Attempts(0), Some(1234), None, Nonce::try_from(&[0u8; 16][..]).unwrap()
      			).is_ok()
      		);
      		assert!(outbound_payments.has_pending_payments());
2:  bf1d03b9 < -:  -------- f: Include Nonce in AwaitingInvoice for context recreation
3:  9b1e056c ! 2:  1cc365ce Introduce enqueue_invoice_request Function
    @@ Commit message
      ## lightning/src/ln/channelmanager.rs ##
     @@ lightning/src/ln/channelmanager.rs: use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutb
      use crate::ln::wire::Encode;
    - use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
    + use crate::offers::invoice::{Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
      use crate::offers::invoice_error::InvoiceError;
     -use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder};
     +use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequest, InvoiceRequestBuilder};
    @@ lightning/src/ln/channelmanager.rs: where
     +	fn enqueue_invoice_request(
     +		&self,
     +		invoice_request: InvoiceRequest,
    -+		reply_paths: Vec<BlindedPath>,
    ++		reply_paths: Vec<BlindedMessagePath>,
     +	) -> Result<(), Bolt12SemanticError> {
      		let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
     -		if !offer.paths().is_empty() {
4:  e9fbabc9 = 3:  8a17319a Introduce handle_message_received in ChannelMessageHandler
5:  656dd95d ! 4:  6a9e9134 Introduce handle_message_received test
    @@ lightning/src/ln/offers_tests.rs: fn creates_and_pays_for_offer_using_one_hop_bl
     +	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(alice_id));
    ++		assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
     +	}
     +	let payment_id = PaymentId([1; 32]);
     +	bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None).unwrap();
    @@ lightning/src/ln/offers_tests.rs: fn creates_and_pays_for_offer_using_one_hop_bl
     +	});
     +	assert_eq!(invoice_request.amount_msats(), None);
     +	assert_ne!(invoice_request.payer_id(), bob_id);
    -+	assert_eq!(reply_path.introduction_node, IntroductionNode::NodeId(bob_id));
    ++	assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(bob_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);
     +
    @@ lightning/src/ln/offers_tests.rs: fn creates_and_pays_for_offer_using_one_hop_bl
     +	assert_eq!(invoice.amount_msats(), 10_000_000);
     +	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(alice_id));
    ++	for path in invoice.payment_paths() {
    ++		assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
     +	}
     +	route_bolt12_payment(bob, &[alice], &invoice);
     +	expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);

@shaavan
Copy link
Contributor Author

shaavan commented Aug 21, 2024

Updated from pr3010.23 to pr3010.24 (diff):
Addressed @vincenzopalazzo, and @jkczyz comments

Changes:

  1. Introduce RetryableInvoiceRequest struct, which contains all the data required to recreate InvoiceRequest Messages.
  2. Upgrade logging level from info to warn for invoice request retry failure case, and improve logging.

lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/msgs.rs Outdated Show resolved Hide resolved
lightning/src/ln/peer_handler.rs Outdated Show resolved Hide resolved
lightning/src/ln/offers_tests.rs Outdated Show resolved Hide resolved
@shaavan
Copy link
Contributor Author

shaavan commented Aug 22, 2024

Updated from pr3010.24 to pr3010.25 (diff):
Addressed @jkczyz comments

Changes:

  1. Remove a redundant clone.
  2. Rename handle_message_received -> message_received, and update docs to align with the function's purpose.
  3. Move the message_received call to handle_message so that it is called before the "message handling" for any kind of message received.
  4. Simplify a check in test.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, feel free to squash.

lightning/src/ln/outbound_payment.rs Outdated Show resolved Hide resolved
lightning/src/ln/msgs.rs Show resolved Hide resolved
@shaavan
Copy link
Contributor Author

shaavan commented Sep 9, 2024

Updated from pr3010.25 to pr3010.26 (diff):
Addressed @TheBlueMatt comments

  1. Update add_new_awaiting_invoice to only update the awaiting_invoice flag if there is some retryable_invoice_request.
  2. Update message_received docs.

@shaavan
Copy link
Contributor Author

shaavan commented Sep 10, 2024

Updated from pr3010.26 to pr3010.27 (diff):
Addressed @jkczyz comment

Changes:

  1. Use a if conditional, instead of map for a more idiomatic construct for retryable_invoice_request.

@shaavan
Copy link
Contributor Author

shaavan commented Sep 12, 2024

Updated from pr3010.27 to pr3010.28 (diff):
Addressed @jkczyz comment

Changes:

  1. Moved the introduced test to the appropriate location.

1. To enable the retry of the Invoice Request message, it's necessary
   to store the essential data required to recreate the message.
2. A new struct is introduced to manage this data, ensuring the
   InvoiceRequest message can be reliably recreated for retries.
3. The addition of an `awaiting_invoice` flag allows tracking of
   retryable invoice requests, preventing the need to lock the
   `pending_outbound_payment` mutex.
1. Separate the logic of forming `invoice_request` messages from
   `invoice_request` and `reply_paths` and enqueueing them into a
   separate function.
2. This logic will be reused in the following commit when reforming
   `invoice_request` messages for retrying.
- Introduce the `message_received` function to manage the
  behavior when a message is received from any peer.
- This function is used within `ChannelManager` to retry `InvoiceRequest`
  messages if we haven't received the corresponding invoice yet.
- This change makes the offer communication robust against sudden
  connection drops where the initial attempt to send the message
  might have failed.
- Add a test to verify the functionality of the handle_message_received
  function.
- Ensure the test covers scenarios where InvoiceRequest messages are retried
  for PendingOutboundPayments after a simulated connection loss.
@shaavan
Copy link
Contributor Author

shaavan commented Sep 12, 2024

Updated from pr3010.28 to pr3010.29 (diff):

Changes:

  1. Rebase on main to resolve merge conflicts.

@TheBlueMatt TheBlueMatt merged commit 1059f5f into lightningdevkit:main Sep 12, 2024
17 of 19 checks passed
@shaavan shaavan deleted the issue2836 branch September 12, 2024 15:58
TheBlueMatt added a commit that referenced this pull request Sep 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Retry InvoiceRequest messages
5 participants