Skip to content

Commit 9de4add

Browse files
committed
Introduce OffersMessageCommons Trait and Implementation
A new trait, `OffersMessageCommons`, is introduced to encapsulate functions that are commonly used by both BOLT12-related functionality and other parts of `ChannelManager`. This enables a clean transition of BOLT12 code to `OffersMessageFlow` by moving shared functions into the new trait, ensuring they remain accessible to both `ChannelManager` and the refactored BOLT12 code.
1 parent 392c320 commit 9de4add

File tree

4 files changed

+196
-6
lines changed

4 files changed

+196
-6
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use bitcoin::hashes::hmac::Hmac;
2828
use bitcoin::hashes::sha256::Hash as Sha256;
2929
use bitcoin::hash_types::{BlockHash, Txid};
3030

31-
use bitcoin::secp256k1::{SecretKey,PublicKey};
31+
use bitcoin::secp256k1::{schnorr, PublicKey, SecretKey};
3232
use bitcoin::secp256k1::Secp256k1;
3333
use bitcoin::{secp256k1, Sequence};
3434

@@ -47,6 +47,7 @@ use crate::events::{self, Event, EventHandler, EventsProvider, InboundChannelFun
4747
// construct one themselves.
4848
use crate::ln::inbound_payment;
4949
use crate::ln::types::ChannelId;
50+
use crate::offers::flow::OffersMessageCommons;
5051
use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
5152
use crate::ln::channel::{self, Channel, ChannelError, ChannelUpdateStatus, FundedChannel, ShutdownResult, UpdateFulfillCommitFetch, OutboundV1Channel, ReconnectionMsg, InboundV1Channel, WithChannelContext};
5253
#[cfg(any(dual_funding, splicing))]
@@ -122,7 +123,7 @@ use core::{cmp, mem};
122123
use core::borrow::Borrow;
123124
use core::cell::RefCell;
124125
use crate::io::Read;
125-
use crate::sync::{Arc, Mutex, RwLock, RwLockReadGuard, FairRwLock, LockTestExt, LockHeldState};
126+
use crate::sync::{Arc, FairRwLock, LockHeldState, LockTestExt, Mutex, MutexGuard, RwLock, RwLockReadGuard};
126127
use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
127128
use core::time::Duration;
128129
use core::ops::Deref;
@@ -9932,6 +9933,88 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
99329933
}
99339934
} }
99349935

9936+
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>
9937+
where
9938+
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
9939+
T::Target: BroadcasterInterface,
9940+
ES::Target: EntropySource,
9941+
NS::Target: NodeSigner,
9942+
SP::Target: SignerProvider,
9943+
F::Target: FeeEstimator,
9944+
R::Target: Router,
9945+
MR::Target: MessageRouter,
9946+
L::Target: Logger,
9947+
{
9948+
fn get_current_blocktime(&self) -> Duration {
9949+
Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64)
9950+
}
9951+
9952+
fn get_peer_for_blinded_path(&self) -> Vec<MessageForwardNode> {
9953+
self.per_peer_state.read().unwrap()
9954+
.iter()
9955+
.map(|(node_id, peer_state)| (node_id, peer_state.lock().unwrap()))
9956+
.filter(|(_, peer)| peer.is_connected)
9957+
.filter(|(_, peer)| peer.latest_features.supports_onion_messages())
9958+
.map(|(node_id, peer)| MessageForwardNode {
9959+
node_id: *node_id,
9960+
short_channel_id: peer.channel_by_id
9961+
.iter()
9962+
.filter(|(_, channel)| channel.context().is_usable())
9963+
.min_by_key(|(_, channel)| channel.context().channel_creation_height)
9964+
.and_then(|(_, channel)| channel.context().get_short_channel_id()),
9965+
})
9966+
.collect::<Vec<_>>()
9967+
}
9968+
9969+
fn create_blinded_payment_paths(
9970+
&self, amount_msats: Option<u64>, payment_secret: PaymentSecret, payment_context: PaymentContext, relative_expiry_time: u32,
9971+
) -> Result<Vec<BlindedPaymentPath>, ()> {
9972+
self.create_blinded_payment_paths(amount_msats, payment_secret, payment_context, relative_expiry_time)
9973+
}
9974+
9975+
fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32,
9976+
min_final_cltv_expiry_delta: Option<u16>) -> Result<(PaymentHash, PaymentSecret), ()> {
9977+
self.create_inbound_payment(min_value_msat, invoice_expiry_delta_secs, min_final_cltv_expiry_delta)
9978+
}
9979+
9980+
fn release_invoice_requests_awaiting_invoice(&self) -> Vec<(PaymentId, RetryableInvoiceRequest)> {
9981+
self.pending_outbound_payments.release_invoice_requests_awaiting_invoice()
9982+
}
9983+
9984+
fn sign_bolt12_invoice(
9985+
&self, invoice: &UnsignedBolt12Invoice,
9986+
) -> Result<schnorr::Signature, ()> {
9987+
self.node_signer.sign_bolt12_invoice(invoice)
9988+
}
9989+
9990+
fn send_payment_for_verified_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError> {
9991+
self.send_payment_for_verified_bolt12_invoice(invoice, payment_id)
9992+
}
9993+
9994+
fn abandon_payment_with_reason(&self, payment_id: PaymentId, reason: PaymentFailureReason) {
9995+
self.abandon_payment_with_reason(payment_id, reason);
9996+
}
9997+
9998+
// ----Temporary Functions----
9999+
// Set of functions temporarily moved to OffersMessageCommons for easier
10000+
// transition of code from ChannelManager to OffersMessageFlow
10001+
10002+
fn get_pending_offers_messages(&self) -> MutexGuard<'_, Vec<(OffersMessage, MessageSendInstructions)>> {
10003+
self.pending_offers_messages.lock().expect("Mutex is locked by other thread.")
10004+
}
10005+
10006+
fn enqueue_invoice_request(&self, invoice_request: InvoiceRequest, reply_paths: Vec<BlindedMessagePath>) -> Result<(), Bolt12SemanticError> {
10007+
self.enqueue_invoice_request(invoice_request, reply_paths)
10008+
}
10009+
10010+
#[cfg(async_payments)]
10011+
fn initiate_async_payment(
10012+
&self, invoice: &StaticInvoice, payment_id: PaymentId
10013+
) -> Result<(), Bolt12PaymentError> {
10014+
self.initiate_async_payment(invoice, payment_id)
10015+
}
10016+
}
10017+
993510018
/// Defines the maximum number of [`OffersMessage`] including different reply paths to be sent
993610019
/// along different paths.
993710020
/// Sending multiple requests increases the chances of successful delivery in case some

lightning/src/ln/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub mod channel;
4141
pub(crate) mod channel;
4242

4343
pub(crate) mod onion_utils;
44-
mod outbound_payment;
44+
pub(crate) mod outbound_payment;
4545
pub mod wire;
4646

4747
#[allow(dead_code)] // TODO(dual_funding): Remove once contribution to V2 channels is enabled.

lightning/src/ln/outbound_payment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub(crate) enum PendingOutboundPayment {
140140
}
141141

142142
#[derive(Clone)]
143-
pub(crate) struct RetryableInvoiceRequest {
143+
pub struct RetryableInvoiceRequest {
144144
pub(crate) invoice_request: InvoiceRequest,
145145
pub(crate) nonce: Nonce,
146146
pub(super) needs_retry: bool,

lightning/src/offers/flow.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,29 @@ use crate::ln::inbound_payment;
1717
use crate::prelude::*;
1818
use crate::sign::EntropySource;
1919
use core::ops::Deref;
20+
use core::time::Duration;
2021

22+
use bitcoin::secp256k1::schnorr;
23+
use lightning_invoice::PaymentSecret;
24+
use types::payment::PaymentHash;
25+
26+
use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode};
27+
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentContext};
28+
use crate::events::PaymentFailureReason;
29+
use crate::ln::channelmanager::{Bolt12PaymentError, PaymentId};
30+
use crate::ln::outbound_payment::RetryableInvoiceRequest;
31+
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
32+
use crate::offers::invoice_request::InvoiceRequest;
33+
use crate::offers::parse::Bolt12SemanticError;
34+
use crate::onion_message::messenger::MessageSendInstructions;
35+
use crate::onion_message::offers::OffersMessage;
36+
use crate::sync::MutexGuard;
2137
use crate::onion_message::messenger::MessageRouter;
2238
use crate::util::logger::Logger;
2339

40+
#[cfg(async_payments)]
41+
use crate::offers::static_invoice::StaticInvoice;
42+
2443
#[cfg(not(c_bindings))]
2544
use {
2645
crate::ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager},
@@ -30,10 +49,98 @@ use {
3049
crate::sync::Arc,
3150
};
3251

33-
/// Functions commonly shared in usage between [`ChannelManager`] & [`OffersMessageFlow`]
52+
/// Functions commonly shared in usage between [`ChannelManager`] & `OffersMessageFlow`
3453
///
3554
/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
36-
pub trait OffersMessageCommons {}
55+
pub trait OffersMessageCommons {
56+
/// Get the current time determined by highest seen timestamp
57+
fn get_current_blocktime(&self) -> Duration;
58+
59+
/// Get the vector of peers that can be used for a blinded path
60+
fn get_peer_for_blinded_path(&self) -> Vec<MessageForwardNode>;
61+
62+
/// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to
63+
/// [`Router::create_blinded_payment_paths`].
64+
///
65+
/// [`Router::create_blinded_payment_paths`]: crate::routing::router::Router::create_blinded_payment_paths
66+
fn create_blinded_payment_paths(
67+
&self, amount_msats: Option<u64>, payment_secret: PaymentSecret, payment_context: PaymentContext, relative_expiry_time: u32,
68+
) -> Result<Vec<BlindedPaymentPath>, ()>;
69+
70+
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
71+
/// to pay us.
72+
///
73+
/// This differs from [`create_inbound_payment_for_hash`] only in that it generates the
74+
/// [`PaymentHash`] and [`PaymentPreimage`] for you.
75+
///
76+
/// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentClaimable`] event, which
77+
/// will have the [`PaymentClaimable::purpose`] return `Some` for [`PaymentPurpose::preimage`]. That
78+
/// should then be passed directly to [`claim_funds`].
79+
///
80+
/// See [`create_inbound_payment_for_hash`] for detailed documentation on behavior and requirements.
81+
///
82+
/// Note that a malicious eavesdropper can intuit whether an inbound payment was created by
83+
/// `create_inbound_payment` or `create_inbound_payment_for_hash` based on runtime.
84+
///
85+
/// # Note
86+
///
87+
/// If you register an inbound payment with this method, then serialize the `ChannelManager`, then
88+
/// deserialize it with a node running 0.0.103 and earlier, the payment will fail to be received.
89+
///
90+
/// Errors if `min_value_msat` is greater than total bitcoin supply.
91+
///
92+
/// If `min_final_cltv_expiry_delta` is set to some value, then the payment will not be receivable
93+
/// on versions of LDK prior to 0.0.114.
94+
///
95+
/// [`claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds
96+
/// [`PaymentClaimable`]: crate::events::Event::PaymentClaimable
97+
/// [`PaymentClaimable::purpose`]: crate::events::Event::PaymentClaimable::purpose
98+
/// [`PaymentPurpose::preimage`]: crate::events::PaymentPurpose::preimage
99+
/// [`create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
100+
/// [`PaymentPreimage`]: crate::types::payment::PaymentPreimage
101+
fn create_inbound_payment(&self, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32,
102+
min_final_cltv_expiry_delta: Option<u16>) -> Result<(PaymentHash, PaymentSecret), ()>;
103+
104+
/// Release invoice requests awaiting invoice
105+
fn release_invoice_requests_awaiting_invoice(&self) -> Vec<(PaymentId, RetryableInvoiceRequest)>;
106+
107+
/// Signs the [`TaggedHash`] of a BOLT 12 invoice.
108+
///
109+
/// May be called by a function passed to [`UnsignedBolt12Invoice::sign`] where `invoice` is the
110+
/// callee.
111+
///
112+
/// Implementors may check that the `invoice` is expected rather than blindly signing the tagged
113+
/// hash. An `Ok` result should sign `invoice.tagged_hash().as_digest()` with the node's signing
114+
/// key or an ephemeral key to preserve privacy, whichever is associated with
115+
/// [`UnsignedBolt12Invoice::signing_pubkey`].
116+
///
117+
/// [`TaggedHash`]: crate::offers::merkle::TaggedHash
118+
fn sign_bolt12_invoice(
119+
&self, invoice: &UnsignedBolt12Invoice,
120+
) -> Result<schnorr::Signature, ()>;
121+
122+
/// Send payment for verified bolt12 invoice
123+
fn send_payment_for_verified_bolt12_invoice(&self, invoice: &Bolt12Invoice, payment_id: PaymentId) -> Result<(), Bolt12PaymentError>;
124+
125+
/// Abandon Payment with Reason
126+
fn abandon_payment_with_reason(&self, payment_id: PaymentId, reason: PaymentFailureReason);
127+
128+
// ----Temporary Functions----
129+
// Set of functions temporarily moved to OffersMessageCommons for easier
130+
// transition of code from ChannelManager to OffersMessageFlow
131+
132+
/// Get pending offers messages
133+
fn get_pending_offers_messages(&self) -> MutexGuard<'_, Vec<(OffersMessage, MessageSendInstructions)>>;
134+
135+
/// Enqueue invoice request
136+
fn enqueue_invoice_request(&self, invoice_request: InvoiceRequest, reply_paths: Vec<BlindedMessagePath>) -> Result<(), Bolt12SemanticError>;
137+
138+
/// Initiate a new async payment
139+
#[cfg(async_payments)]
140+
fn initiate_async_payment(
141+
&self, invoice: &StaticInvoice, payment_id: PaymentId
142+
) -> Result<(), Bolt12PaymentError>;
143+
}
37144

38145
/// [`SimpleArcOffersMessageFlow`] is useful when you need a [`OffersMessageFlow`] with a static lifetime, e.g.
39146
/// when you're using `lightning-net-tokio` (since `tokio::spawn` requires parameters with static

0 commit comments

Comments
 (0)