Skip to content

Commit 4f95892

Browse files
committed
Move create_refund_builder to OffersMessageFlow
1 parent 3173487 commit 4f95892

File tree

5 files changed

+203
-177
lines changed

5 files changed

+203
-177
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 19 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder};
6969
use crate::offers::nonce::Nonce;
7070
use crate::offers::offer::Offer;
7171
use crate::offers::parse::Bolt12SemanticError;
72-
use crate::offers::refund::{Refund, RefundBuilder};
72+
use crate::offers::refund::Refund;
7373
use crate::offers::signer;
7474
#[cfg(async_payments)]
7575
use crate::offers::static_invoice::StaticInvoice;
@@ -1953,7 +1953,7 @@ where
19531953
/// ```
19541954
/// # use lightning::events::{Event, EventsProvider};
19551955
/// # use lightning::types::payment::PaymentHash;
1956-
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry};
1956+
/// # use lightning::ln::channelmanager::{AChannelManager, OffersMessageCommons, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry};
19571957
/// # use lightning::routing::router::RouteParameters;
19581958
/// #
19591959
/// # fn example<T: AChannelManager>(
@@ -2007,7 +2007,7 @@ where
20072007
///
20082008
/// ```
20092009
/// # use lightning::events::{Event, EventsProvider};
2010-
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
2010+
/// # use lightning::ln::channelmanager::{AChannelManager, OffersMessageCommons, PaymentId, RecentPaymentDetails, Retry};
20112011
/// # use lightning::offers::offer::Offer;
20122012
/// #
20132013
/// # fn example<T: AChannelManager>(
@@ -2054,67 +2054,8 @@ where
20542054
/// ```
20552055
///
20562056
/// ## BOLT 12 Refunds
2057-
///
2058-
/// A [`Refund`] is a request for an invoice to be paid. Like *paying* for an [`Offer`], *creating*
2059-
/// a [`Refund`] involves maintaining state since it represents a future outbound payment.
2060-
/// Therefore, use [`create_refund_builder`] when creating one, otherwise [`ChannelManager`] will
2061-
/// refuse to pay any corresponding [`Bolt12Invoice`] that it receives.
2062-
///
2063-
/// ```
2064-
/// # use core::time::Duration;
2065-
/// # use lightning::events::{Event, EventsProvider};
2066-
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
2067-
/// # use lightning::offers::parse::Bolt12SemanticError;
2068-
/// #
2069-
/// # fn example<T: AChannelManager>(
2070-
/// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
2071-
/// # max_total_routing_fee_msat: Option<u64>
2072-
/// # ) -> Result<(), Bolt12SemanticError> {
2073-
/// # let channel_manager = channel_manager.get_cm();
2074-
/// let payment_id = PaymentId([42; 32]);
2075-
/// let refund = channel_manager
2076-
/// .create_refund_builder(
2077-
/// amount_msats, absolute_expiry, payment_id, retry, max_total_routing_fee_msat
2078-
/// )?
2079-
/// # ;
2080-
/// # // Needed for compiling for c_bindings
2081-
/// # let builder: lightning::offers::refund::RefundBuilder<_> = refund.into();
2082-
/// # let refund = builder
2083-
/// .description("coffee".to_string())
2084-
/// .payer_note("refund for order 1234".to_string())
2085-
/// .build()?;
2086-
/// let bech32_refund = refund.to_string();
2087-
///
2088-
/// // First the payment will be waiting on an invoice
2089-
/// let expected_payment_id = payment_id;
2090-
/// assert!(
2091-
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
2092-
/// details,
2093-
/// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
2094-
/// )).is_some()
2095-
/// );
2096-
///
2097-
/// // Once the invoice is received, a payment will be sent
2098-
/// assert!(
2099-
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
2100-
/// details,
2101-
/// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
2102-
/// )).is_some()
2103-
/// );
2104-
///
2105-
/// // On the event processing thread
2106-
/// channel_manager.process_pending_events(&|event| {
2107-
/// match event {
2108-
/// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
2109-
/// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
2110-
/// // ...
2111-
/// # _ => {},
2112-
/// }
2113-
/// Ok(())
2114-
/// });
2115-
/// # Ok(())
2116-
/// # }
2117-
/// ```
2057+
///
2058+
/// For more information on creating refunds, see [`create_refund_builder`].
21182059
///
21192060
/// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
21202061
/// *creating* an [`Offer`], this is stateless as it represents an inbound payment.
@@ -2242,7 +2183,6 @@ where
22422183
/// [`offers`]: crate::offers
22432184
/// [`pay_for_offer`]: Self::pay_for_offer
22442185
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
2245-
/// [`create_refund_builder`]: Self::create_refund_builder
22462186
/// [`request_refund_payment`]: Self::request_refund_payment
22472187
/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
22482188
/// [`funding_created`]: msgs::FundingCreated
@@ -2252,6 +2192,7 @@ where
22522192
/// [`ChannelUpdate`]: msgs::ChannelUpdate
22532193
/// [`read`]: ReadableArgs::read
22542194
/// [`create_offer_builder`]: crate::offers::flow::OffersMessageFlow::create_offer_builder
2195+
/// [`create_refund_builder`]: crate::offers::flow::OffersMessageFlow::create_refund_builder
22552196
//
22562197
// Lock order:
22572198
// The tree structure below illustrates the lock order requirements for the different locks of the
@@ -2742,12 +2683,14 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
27422683
/// The maximum expiration from the current time where an [`Offer`] or [`Refund`] is considered
27432684
/// short-lived, while anything with a greater expiration is considered long-lived.
27442685
///
2745-
/// Using [`OffersMessageFlow::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
2686+
/// Using [`OffersMessageFlow::create_offer_builder`] or [`OffersMessageFlow::create_refund_builder`],
27462687
/// will included a [`BlindedMessagePath`] created using:
27472688
/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
27482689
/// - [`MessageRouter::create_blinded_paths`] when long-lived.
27492690
///
27502691
/// [`OffersMessageFlow::create_offer_builder`]: crate::offers::flow::OffersMessageFlow::create_offer_builder
2692+
/// [`OffersMessageFlow::create_refund_builder`]: crate::offers::flow::OffersMessageFlow::create_refund_builder
2693+
///
27512694
///
27522695
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
27532696
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
@@ -9339,87 +9282,6 @@ impl Default for Bolt11InvoiceParameters {
93399282
}
93409283
}
93419284

9342-
macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
9343-
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
9344-
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
9345-
///
9346-
/// # Payment
9347-
///
9348-
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
9349-
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
9350-
///
9351-
/// The builder will have the provided expiration set. Any changes to the expiration on the
9352-
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
9353-
/// block time minus two hours is used for the current time when determining if the refund has
9354-
/// expired.
9355-
///
9356-
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
9357-
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
9358-
/// with an [`Event::PaymentFailed`].
9359-
///
9360-
/// If `max_total_routing_fee_msat` is not specified, The default from
9361-
/// [`RouteParameters::from_payment_params_and_value`] is applied.
9362-
///
9363-
/// # Privacy
9364-
///
9365-
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
9366-
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
9367-
/// privacy implications as well as those of the parameterized [`Router`], which implements
9368-
/// [`MessageRouter`].
9369-
///
9370-
/// Also, uses a derived payer id in the refund for payer privacy.
9371-
///
9372-
/// # Limitations
9373-
///
9374-
/// Requires a direct connection to an introduction node in the responding
9375-
/// [`Bolt12Invoice::payment_paths`].
9376-
///
9377-
/// # Errors
9378-
///
9379-
/// Errors if:
9380-
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
9381-
/// - `amount_msats` is invalid, or
9382-
/// - the parameterized [`Router`] is unable to create a blinded path for the refund.
9383-
///
9384-
/// [`Refund`]: crate::offers::refund::Refund
9385-
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
9386-
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
9387-
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
9388-
pub fn create_refund_builder(
9389-
&$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
9390-
retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
9391-
) -> Result<$builder, Bolt12SemanticError> {
9392-
let node_id = $self.get_our_node_id();
9393-
let expanded_key = &$self.inbound_payment_key;
9394-
let entropy = &*$self.entropy_source;
9395-
let secp_ctx = &$self.secp_ctx;
9396-
9397-
let nonce = Nonce::from_entropy_source(entropy);
9398-
let context = OffersContext::OutboundPayment { payment_id, nonce, hmac: None };
9399-
let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry))
9400-
.and_then(|paths| paths.into_iter().next().ok_or(()))
9401-
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
9402-
9403-
let builder = RefundBuilder::deriving_signing_pubkey(
9404-
node_id, expanded_key, nonce, secp_ctx, amount_msats, payment_id
9405-
)?
9406-
.chain_hash($self.chain_hash)
9407-
.absolute_expiry(absolute_expiry)
9408-
.path(path);
9409-
9410-
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
9411-
9412-
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
9413-
$self.pending_outbound_payments
9414-
.add_new_awaiting_invoice(
9415-
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, None,
9416-
)
9417-
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
9418-
9419-
Ok(builder.into())
9420-
}
9421-
} }
9422-
94239285
/// Functions commonly shared in usage between [`ChannelManager`] & [`OffersMessageFlow`]
94249286
///
94259287
/// [`OffersMessageFlow`]: crate::offers::flow::OffersMessageFlow
@@ -9535,6 +9397,9 @@ pub trait OffersMessageCommons {
95359397

95369398
/// Get the [`ChainHash`] of the chain
95379399
fn get_chain_hash(&self) -> ChainHash;
9400+
9401+
/// Add new awaiting invoice
9402+
fn add_new_awaiting_invoice(&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>, retryable_invoice_request: Option<RetryableInvoiceRequest>) -> Result<(), ()>;
95389403
}
95399404

95409405
impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, MR: Deref, L: Deref> OffersMessageCommons for ChannelManager<M, T, ES, NS, SP, F, R, MR, L>
@@ -9716,6 +9581,13 @@ where
97169581
fn get_chain_hash(&self) -> ChainHash {
97179582
self.chain_hash
97189583
}
9584+
9585+
fn add_new_awaiting_invoice(&self, payment_id: PaymentId, expiration: StaleExpiration, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>, retryable_invoice_request: Option<RetryableInvoiceRequest>) -> Result<(), ()> {
9586+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
9587+
self.pending_outbound_payments.add_new_awaiting_invoice (
9588+
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, retryable_invoice_request,
9589+
)
9590+
}
97199591
}
97209592

97219593
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
@@ -9737,12 +9609,6 @@ where
97379609
MR::Target: MessageRouter,
97389610
L::Target: Logger,
97399611
{
9740-
#[cfg(not(c_bindings))]
9741-
create_refund_builder!(self, RefundBuilder<secp256k1::All>);
9742-
9743-
#[cfg(c_bindings)]
9744-
create_refund_builder!(self, RefundMaybeWithDerivedMetadataBuilder);
9745-
97469612
/// Pays for an [`Offer`] using the given parameters by creating an [`InvoiceRequest`] and
97479613
/// enqueuing it to be sent via an onion message. [`ChannelManager`] will pay the actual
97489614
/// [`Bolt12Invoice`] once it is received.

lightning/src/ln/offers_tests.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ fn creates_short_lived_refund() {
453453

454454
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
455455
let payment_id = PaymentId([1; 32]);
456-
let refund = bob.node
456+
let refund = bob.offers_handler
457457
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
458458
.unwrap()
459459
.build().unwrap();
@@ -482,7 +482,7 @@ fn creates_long_lived_refund() {
482482
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY
483483
+ Duration::from_secs(1);
484484
let payment_id = PaymentId([1; 32]);
485-
let refund = bob.node
485+
let refund = bob.offers_handler
486486
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
487487
.unwrap()
488488
.build().unwrap();
@@ -641,7 +641,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() {
641641

642642
let absolute_expiry = Duration::from_secs(u64::MAX);
643643
let payment_id = PaymentId([1; 32]);
644-
let refund = david.node
644+
let refund = david.offers_handler
645645
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
646646
.unwrap()
647647
.build().unwrap();
@@ -770,7 +770,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() {
770770

771771
let absolute_expiry = Duration::from_secs(u64::MAX);
772772
let payment_id = PaymentId([1; 32]);
773-
let refund = bob.node
773+
let refund = bob.offers_handler
774774
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
775775
.unwrap()
776776
.build().unwrap();
@@ -879,7 +879,7 @@ fn pays_for_refund_without_blinded_paths() {
879879

880880
let absolute_expiry = Duration::from_secs(u64::MAX);
881881
let payment_id = PaymentId([1; 32]);
882-
let refund = bob.node
882+
let refund = bob.offers_handler
883883
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
884884
.unwrap()
885885
.clear_paths()
@@ -1034,7 +1034,7 @@ fn send_invoice_for_refund_with_distinct_reply_path() {
10341034

10351035
let absolute_expiry = Duration::from_secs(u64::MAX);
10361036
let payment_id = PaymentId([1; 32]);
1037-
let refund = alice.node
1037+
let refund = alice.offers_handler
10381038
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
10391039
.unwrap()
10401040
.build().unwrap();
@@ -1313,7 +1313,7 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
13131313

13141314
let absolute_expiry = Duration::from_secs(u64::MAX);
13151315
let payment_id = PaymentId([1; 32]);
1316-
let refund = bob.node
1316+
let refund = bob.offers_handler
13171317
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
13181318
.unwrap()
13191319
.build().unwrap();
@@ -1596,7 +1596,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
15961596

15971597
let absolute_expiry = Duration::from_secs(u64::MAX);
15981598
let payment_id = PaymentId([1; 32]);
1599-
let refund = david.node
1599+
let refund = david.offers_handler
16001600
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
16011601
.unwrap()
16021602
.build().unwrap();
@@ -1630,7 +1630,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
16301630
// Send the invoice to David using an invalid blinded path.
16311631
let invalid_path = refund.paths().first().unwrap().clone();
16321632
let payment_id = PaymentId([2; 32]);
1633-
let refund = david.node
1633+
let refund = david.offers_handler
16341634
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
16351635
.unwrap()
16361636
.build().unwrap();
@@ -1757,7 +1757,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
17571757

17581758
let absolute_expiry = david.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
17591759
let payment_id = PaymentId([1; 32]);
1760-
match david.node.create_refund_builder(
1760+
match david.offers_handler.create_refund_builder(
17611761
10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None
17621762
) {
17631763
Ok(_) => panic!("Expected error"),
@@ -1768,7 +1768,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
17681768
args.send_channel_ready = (true, true);
17691769
reconnect_nodes(args);
17701770

1771-
let refund = david.node
1771+
let refund = david.offers_handler
17721772
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
17731773
.unwrap()
17741774
.build().unwrap();
@@ -1826,7 +1826,7 @@ fn fails_sending_invoice_with_unsupported_chain_for_refund() {
18261826

18271827
let absolute_expiry = Duration::from_secs(u64::MAX);
18281828
let payment_id = PaymentId([1; 32]);
1829-
let refund = bob.node
1829+
let refund = bob.offers_handler
18301830
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
18311831
.unwrap()
18321832
.chain(Network::Signet)
@@ -1924,13 +1924,13 @@ fn fails_creating_refund_with_duplicate_payment_id() {
19241924
let absolute_expiry = Duration::from_secs(u64::MAX);
19251925
let payment_id = PaymentId([1; 32]);
19261926
assert!(
1927-
nodes[0].node.create_refund_builder(
1927+
nodes[0].offers_handler.create_refund_builder(
19281928
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
19291929
).is_ok()
19301930
);
19311931
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
19321932

1933-
match nodes[0].node.create_refund_builder(
1933+
match nodes[0].offers_handler.create_refund_builder(
19341934
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
19351935
) {
19361936
Ok(_) => panic!("Expected error"),
@@ -2050,7 +2050,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {
20502050

20512051
let absolute_expiry = Duration::from_secs(u64::MAX);
20522052
let payment_id = PaymentId([1; 32]);
2053-
let refund = david.node
2053+
let refund = david.offers_handler
20542054
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
20552055
.unwrap()
20562056
.build().unwrap();
@@ -2099,7 +2099,7 @@ fn fails_paying_invoice_more_than_once() {
20992099

21002100
let absolute_expiry = Duration::from_secs(u64::MAX);
21012101
let payment_id = PaymentId([1; 32]);
2102-
let refund = david.node
2102+
let refund = david.offers_handler
21032103
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
21042104
.unwrap()
21052105
.build().unwrap();

0 commit comments

Comments
 (0)