Skip to content

Commit 6768e36

Browse files
committed
Move create_refund_builder to OffersMessageFlow
1 parent 54e0699 commit 6768e36

File tree

5 files changed

+206
-176
lines changed

5 files changed

+206
-176
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 16 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder};
6868
use crate::offers::nonce::Nonce;
6969
use crate::offers::offer::Offer;
7070
use crate::offers::parse::Bolt12SemanticError;
71-
use crate::offers::refund::{Refund, RefundBuilder};
71+
use crate::offers::refund::Refund;
7272
use crate::offers::signer;
7373
#[cfg(async_payments)]
7474
use crate::offers::static_invoice::StaticInvoice;
@@ -100,8 +100,6 @@ use {
100100
crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters},
101101
crate::sign::KeysManager,
102102
};
103-
#[cfg(c_bindings)]
104-
use crate::offers::refund::RefundMaybeWithDerivedMetadataBuilder;
105103

106104
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, CreationError, Currency, Description, InvoiceBuilder as Bolt11InvoiceBuilder, SignOrCreationError, DEFAULT_EXPIRY_TIME};
107105

@@ -1957,6 +1955,7 @@ where
19571955
/// # use lightning::events::{Event, EventsProvider};
19581956
/// # use lightning::types::payment::PaymentHash;
19591957
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry};
1958+
/// # use lightning::offers::flow::OffersMessageCommons;
19601959
/// # use lightning::routing::router::RouteParameters;
19611960
/// #
19621961
/// # fn example<T: AChannelManager>(
@@ -2011,6 +2010,7 @@ where
20112010
/// ```
20122011
/// # use lightning::events::{Event, EventsProvider};
20132012
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
2013+
/// # use lightning::offers::flow::OffersMessageCommons;
20142014
/// # use lightning::offers::offer::Offer;
20152015
/// #
20162016
/// # fn example<T: AChannelManager>(
@@ -2057,67 +2057,8 @@ where
20572057
/// ```
20582058
///
20592059
/// ## BOLT 12 Refunds
2060-
///
2061-
/// A [`Refund`] is a request for an invoice to be paid. Like *paying* for an [`Offer`], *creating*
2062-
/// a [`Refund`] involves maintaining state since it represents a future outbound payment.
2063-
/// Therefore, use [`create_refund_builder`] when creating one, otherwise [`ChannelManager`] will
2064-
/// refuse to pay any corresponding [`Bolt12Invoice`] that it receives.
2065-
///
2066-
/// ```
2067-
/// # use core::time::Duration;
2068-
/// # use lightning::events::{Event, EventsProvider};
2069-
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
2070-
/// # use lightning::offers::parse::Bolt12SemanticError;
2071-
/// #
2072-
/// # fn example<T: AChannelManager>(
2073-
/// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
2074-
/// # max_total_routing_fee_msat: Option<u64>
2075-
/// # ) -> Result<(), Bolt12SemanticError> {
2076-
/// # let channel_manager = channel_manager.get_cm();
2077-
/// let payment_id = PaymentId([42; 32]);
2078-
/// let refund = channel_manager
2079-
/// .create_refund_builder(
2080-
/// amount_msats, absolute_expiry, payment_id, retry, max_total_routing_fee_msat
2081-
/// )?
2082-
/// # ;
2083-
/// # // Needed for compiling for c_bindings
2084-
/// # let builder: lightning::offers::refund::RefundBuilder<_> = refund.into();
2085-
/// # let refund = builder
2086-
/// .description("coffee".to_string())
2087-
/// .payer_note("refund for order 1234".to_string())
2088-
/// .build()?;
2089-
/// let bech32_refund = refund.to_string();
2090-
///
2091-
/// // First the payment will be waiting on an invoice
2092-
/// let expected_payment_id = payment_id;
2093-
/// assert!(
2094-
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
2095-
/// details,
2096-
/// RecentPaymentDetails::AwaitingInvoice { payment_id: expected_payment_id }
2097-
/// )).is_some()
2098-
/// );
2099-
///
2100-
/// // Once the invoice is received, a payment will be sent
2101-
/// assert!(
2102-
/// channel_manager.list_recent_payments().iter().find(|details| matches!(
2103-
/// details,
2104-
/// RecentPaymentDetails::Pending { payment_id: expected_payment_id, .. }
2105-
/// )).is_some()
2106-
/// );
2107-
///
2108-
/// // On the event processing thread
2109-
/// channel_manager.process_pending_events(&|event| {
2110-
/// match event {
2111-
/// Event::PaymentSent { payment_id: Some(payment_id), .. } => println!("Paid {}", payment_id),
2112-
/// Event::PaymentFailed { payment_id, .. } => println!("Failed paying {}", payment_id),
2113-
/// // ...
2114-
/// # _ => {},
2115-
/// }
2116-
/// Ok(())
2117-
/// });
2118-
/// # Ok(())
2119-
/// # }
2120-
/// ```
2060+
///
2061+
/// For more information on creating refunds, see [`create_refund_builder`].
21212062
///
21222063
/// Use [`request_refund_payment`] to send a [`Bolt12Invoice`] for receiving the refund. Similar to
21232064
/// *creating* an [`Offer`], this is stateless as it represents an inbound payment.
@@ -2246,7 +2187,6 @@ where
22462187
/// [`offers`]: crate::offers
22472188
/// [`pay_for_offer`]: Self::pay_for_offer
22482189
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
2249-
/// [`create_refund_builder`]: Self::create_refund_builder
22502190
/// [`request_refund_payment`]: Self::request_refund_payment
22512191
/// [`peer_disconnected`]: msgs::ChannelMessageHandler::peer_disconnected
22522192
/// [`funding_created`]: msgs::FundingCreated
@@ -2256,6 +2196,7 @@ where
22562196
/// [`ChannelUpdate`]: msgs::ChannelUpdate
22572197
/// [`read`]: ReadableArgs::read
22582198
/// [`create_offer_builder`]: crate::offers::flow::OffersMessageFlow::create_offer_builder
2199+
/// [`create_refund_builder`]: crate::offers::flow::OffersMessageFlow::create_refund_builder
22592200
//
22602201
// Lock order:
22612202
// The tree structure below illustrates the lock order requirements for the different locks of the
@@ -2752,12 +2693,14 @@ const MAX_NO_CHANNEL_PEERS: usize = 250;
27522693
/// The maximum expiration from the current time where an [`Offer`] or [`Refund`] is considered
27532694
/// short-lived, while anything with a greater expiration is considered long-lived.
27542695
///
2755-
/// Using [`OffersMessageFlow::create_offer_builder`] or [`ChannelManager::create_refund_builder`],
2696+
/// Using [`OffersMessageFlow::create_offer_builder`] or [`OffersMessageFlow::create_refund_builder`],
27562697
/// will included a [`BlindedMessagePath`] created using:
27572698
/// - [`MessageRouter::create_compact_blinded_paths`] when short-lived, and
27582699
/// - [`MessageRouter::create_blinded_paths`] when long-lived.
27592700
///
27602701
/// [`OffersMessageFlow::create_offer_builder`]: crate::offers::flow::OffersMessageFlow::create_offer_builder
2702+
/// [`OffersMessageFlow::create_refund_builder`]: crate::offers::flow::OffersMessageFlow::create_refund_builder
2703+
///
27612704
///
27622705
/// Using compact [`BlindedMessagePath`]s may provide better privacy as the [`MessageRouter`] could select
27632706
/// more hops. However, since they use short channel ids instead of pubkeys, they are more likely to
@@ -9593,87 +9536,6 @@ impl Default for Bolt11InvoiceParameters {
95939536
}
95949537
}
95959538

9596-
macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
9597-
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
9598-
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
9599-
///
9600-
/// # Payment
9601-
///
9602-
/// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
9603-
/// See [Avoiding Duplicate Payments] for other requirements once the payment has been sent.
9604-
///
9605-
/// The builder will have the provided expiration set. Any changes to the expiration on the
9606-
/// returned builder will not be honored by [`ChannelManager`]. For non-`std`, the highest seen
9607-
/// block time minus two hours is used for the current time when determining if the refund has
9608-
/// expired.
9609-
///
9610-
/// To revoke the refund, use [`ChannelManager::abandon_payment`] prior to receiving the
9611-
/// invoice. If abandoned, or an invoice isn't received before expiration, the payment will fail
9612-
/// with an [`Event::PaymentFailed`].
9613-
///
9614-
/// If `max_total_routing_fee_msat` is not specified, The default from
9615-
/// [`RouteParameters::from_payment_params_and_value`] is applied.
9616-
///
9617-
/// # Privacy
9618-
///
9619-
/// Uses [`MessageRouter`] to construct a [`BlindedMessagePath`] for the refund based on the given
9620-
/// `absolute_expiry` according to [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. See those docs for
9621-
/// privacy implications as well as those of the parameterized [`Router`], which implements
9622-
/// [`MessageRouter`].
9623-
///
9624-
/// Also, uses a derived payer id in the refund for payer privacy.
9625-
///
9626-
/// # Limitations
9627-
///
9628-
/// Requires a direct connection to an introduction node in the responding
9629-
/// [`Bolt12Invoice::payment_paths`].
9630-
///
9631-
/// # Errors
9632-
///
9633-
/// Errors if:
9634-
/// - a duplicate `payment_id` is provided given the caveats in the aforementioned link,
9635-
/// - `amount_msats` is invalid, or
9636-
/// - the parameterized [`Router`] is unable to create a blinded path for the refund.
9637-
///
9638-
/// [`Refund`]: crate::offers::refund::Refund
9639-
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
9640-
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
9641-
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
9642-
pub fn create_refund_builder(
9643-
&$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
9644-
retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
9645-
) -> Result<$builder, Bolt12SemanticError> {
9646-
let node_id = $self.get_our_node_id();
9647-
let expanded_key = &$self.inbound_payment_key;
9648-
let entropy = &*$self.entropy_source;
9649-
let secp_ctx = &$self.secp_ctx;
9650-
9651-
let nonce = Nonce::from_entropy_source(entropy);
9652-
let context = OffersContext::OutboundPayment { payment_id, nonce, hmac: None };
9653-
let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry))
9654-
.and_then(|paths| paths.into_iter().next().ok_or(()))
9655-
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
9656-
9657-
let builder = RefundBuilder::deriving_signing_pubkey(
9658-
node_id, expanded_key, nonce, secp_ctx, amount_msats, payment_id
9659-
)?
9660-
.chain_hash($self.chain_hash)
9661-
.absolute_expiry(absolute_expiry)
9662-
.path(path);
9663-
9664-
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop($self);
9665-
9666-
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
9667-
$self.pending_outbound_payments
9668-
.add_new_awaiting_invoice(
9669-
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, None,
9670-
)
9671-
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
9672-
9673-
Ok(builder.into())
9674-
}
9675-
} }
9676-
96779539
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>
96789540
where
96799541
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
@@ -9897,6 +9759,13 @@ where
98979759
fn get_chain_hash(&self) -> ChainHash {
98989760
self.chain_hash
98999761
}
9762+
9763+
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<(), ()> {
9764+
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
9765+
self.pending_outbound_payments.add_new_awaiting_invoice (
9766+
payment_id, expiration, retry_strategy, max_total_routing_fee_msat, retryable_invoice_request,
9767+
)
9768+
}
99009769
}
99019770

99029771
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
@@ -9918,12 +9787,6 @@ where
99189787
MR::Target: MessageRouter,
99199788
L::Target: Logger,
99209789
{
9921-
#[cfg(not(c_bindings))]
9922-
create_refund_builder!(self, RefundBuilder<secp256k1::All>);
9923-
9924-
#[cfg(c_bindings)]
9925-
create_refund_builder!(self, RefundMaybeWithDerivedMetadataBuilder);
9926-
99279790
/// Pays for an [`Offer`] using the given parameters by creating an [`InvoiceRequest`] and
99289791
/// enqueuing it to be sent via an onion message. [`ChannelManager`] will pay the actual
99299792
/// [`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
@@ -452,7 +452,7 @@ fn creates_short_lived_refund() {
452452

453453
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
454454
let payment_id = PaymentId([1; 32]);
455-
let refund = bob.node
455+
let refund = bob.offers_handler
456456
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
457457
.unwrap()
458458
.build().unwrap();
@@ -481,7 +481,7 @@ fn creates_long_lived_refund() {
481481
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY
482482
+ Duration::from_secs(1);
483483
let payment_id = PaymentId([1; 32]);
484-
let refund = bob.node
484+
let refund = bob.offers_handler
485485
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
486486
.unwrap()
487487
.build().unwrap();
@@ -640,7 +640,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() {
640640

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

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

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

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

12371237
let absolute_expiry = Duration::from_secs(u64::MAX);
12381238
let payment_id = PaymentId([1; 32]);
1239-
let refund = bob.node
1239+
let refund = bob.offers_handler
12401240
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
12411241
.unwrap()
12421242
.build().unwrap();
@@ -1519,7 +1519,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
15191519

15201520
let absolute_expiry = Duration::from_secs(u64::MAX);
15211521
let payment_id = PaymentId([1; 32]);
1522-
let refund = david.node
1522+
let refund = david.offers_handler
15231523
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
15241524
.unwrap()
15251525
.build().unwrap();
@@ -1553,7 +1553,7 @@ fn fails_authentication_when_handling_invoice_for_refund() {
15531553
// Send the invoice to David using an invalid blinded path.
15541554
let invalid_path = refund.paths().first().unwrap().clone();
15551555
let payment_id = PaymentId([2; 32]);
1556-
let refund = david.node
1556+
let refund = david.offers_handler
15571557
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
15581558
.unwrap()
15591559
.build().unwrap();
@@ -1680,7 +1680,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
16801680

16811681
let absolute_expiry = david.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
16821682
let payment_id = PaymentId([1; 32]);
1683-
match david.node.create_refund_builder(
1683+
match david.offers_handler.create_refund_builder(
16841684
10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None
16851685
) {
16861686
Ok(_) => panic!("Expected error"),
@@ -1691,7 +1691,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
16911691
args.send_channel_ready = (true, true);
16921692
reconnect_nodes(args);
16931693

1694-
let refund = david.node
1694+
let refund = david.offers_handler
16951695
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
16961696
.unwrap()
16971697
.build().unwrap();
@@ -1749,7 +1749,7 @@ fn fails_sending_invoice_with_unsupported_chain_for_refund() {
17491749

17501750
let absolute_expiry = Duration::from_secs(u64::MAX);
17511751
let payment_id = PaymentId([1; 32]);
1752-
let refund = bob.node
1752+
let refund = bob.offers_handler
17531753
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
17541754
.unwrap()
17551755
.chain(Network::Signet)
@@ -1847,13 +1847,13 @@ fn fails_creating_refund_with_duplicate_payment_id() {
18471847
let absolute_expiry = Duration::from_secs(u64::MAX);
18481848
let payment_id = PaymentId([1; 32]);
18491849
assert!(
1850-
nodes[0].node.create_refund_builder(
1850+
nodes[0].offers_handler.create_refund_builder(
18511851
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
18521852
).is_ok()
18531853
);
18541854
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
18551855

1856-
match nodes[0].node.create_refund_builder(
1856+
match nodes[0].offers_handler.create_refund_builder(
18571857
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
18581858
) {
18591859
Ok(_) => panic!("Expected error"),
@@ -1973,7 +1973,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {
19731973

19741974
let absolute_expiry = Duration::from_secs(u64::MAX);
19751975
let payment_id = PaymentId([1; 32]);
1976-
let refund = david.node
1976+
let refund = david.offers_handler
19771977
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
19781978
.unwrap()
19791979
.build().unwrap();
@@ -2022,7 +2022,7 @@ fn fails_paying_invoice_more_than_once() {
20222022

20232023
let absolute_expiry = Duration::from_secs(u64::MAX);
20242024
let payment_id = PaymentId([1; 32]);
2025-
let refund = david.node
2025+
let refund = david.offers_handler
20262026
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
20272027
.unwrap()
20282028
.build().unwrap();

0 commit comments

Comments
 (0)