Skip to content

Commit

Permalink
Add Bolt12CreationError error type to ChannelManager
Browse files Browse the repository at this point in the history
Introduced the Bolt12CreationError error type for bolt12
errors that occur outside the builder. This error type is
used in the ChannelManger functions. I moved, DuplicatePayment,
and InsufficientLiquidity out of Bolt12SemanticsErrors into
the new error type as well.

Additionally, I updated the code to replace occurrences
where we replaced Bolt12SemanticsErrors with the new
Bolt12CreationError type throughout the relevant files.
  • Loading branch information
slanesuke committed Jul 24, 2024
1 parent 1916fc4 commit f2bc100
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 37 deletions.
60 changes: 39 additions & 21 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1700,10 +1700,9 @@ where
///
/// ```
/// # use lightning::events::{Event, EventsProvider, PaymentPurpose};
/// # use lightning::ln::channelmanager::AChannelManager;
/// # use lightning::offers::parse::Bolt12SemanticError;
/// # use lightning::ln::channelmanager::{AChannelManager, Bolt12CreationError};
/// #
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12SemanticError> {
/// # fn example<T: AChannelManager>(channel_manager: T) -> Result<(), Bolt12CreationError> {
/// # let channel_manager = channel_manager.get_cm();
/// # let absolute_expiry = None;
/// let offer = channel_manager
Expand Down Expand Up @@ -1805,13 +1804,12 @@ where
/// ```
/// # use core::time::Duration;
/// # use lightning::events::{Event, EventsProvider};
/// # use lightning::ln::channelmanager::{AChannelManager, PaymentId, RecentPaymentDetails, Retry};
/// # use lightning::offers::parse::Bolt12SemanticError;
/// # use lightning::ln::channelmanager::{AChannelManager, Bolt12CreationError, PaymentId, RecentPaymentDetails, Retry};
/// #
/// # fn example<T: AChannelManager>(
/// # channel_manager: T, amount_msats: u64, absolute_expiry: Duration, retry: Retry,
/// # max_total_routing_fee_msat: Option<u64>
/// # ) -> Result<(), Bolt12SemanticError> {
/// # ) -> Result<(), Bolt12CreationError> {
/// # let channel_manager = channel_manager.get_cm();
/// let payment_id = PaymentId([42; 32]);
/// let refund = channel_manager
Expand Down Expand Up @@ -2526,6 +2524,26 @@ pub enum RecentPaymentDetails {
},
}

/// Error during creation and handling of BOLT 12 related payments.
#[derive(Debug, Clone, PartialEq)]
pub enum Bolt12CreationError {
/// Error from BOLT 12 semantic checks.
InvalidSemantics(Bolt12SemanticError),
/// The payment id for a refund or request is already in use.
DuplicatePaymentId,
/// There is insufficient liquidity to complete the payment.
InsufficientLiquidity,
/// Failed to create a blinded path.
BlindedPathCreationFailed,
}

impl From<Bolt12SemanticError> for Bolt12CreationError {
fn from(err: Bolt12SemanticError) -> Self {
Bolt12CreationError::InvalidSemantics(err)
}
}


/// Route hints used in constructing invoices for [phantom node payents].
///
/// [phantom node payments]: crate::sign::PhantomKeysManager
Expand Down Expand Up @@ -8801,7 +8819,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub fn create_offer_builder(
&$self, absolute_expiry: Option<Duration>
) -> Result<$builder, Bolt12SemanticError> {
) -> Result<$builder, Bolt12CreationError> {
let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key;
let entropy = &*$self.entropy_source;
Expand All @@ -8811,7 +8829,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
let context = OffersContext::InvoiceRequest { nonce };
let path = $self.create_blinded_paths_using_absolute_expiry(context, absolute_expiry)
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
.map_err(|_| Bolt12CreationError::BlindedPathCreationFailed)?;
let builder = OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)
.chain_hash($self.chain_hash)
.path(path);
Expand Down Expand Up @@ -8874,7 +8892,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
pub fn create_refund_builder(
&$self, amount_msats: u64, absolute_expiry: Duration, payment_id: PaymentId,
retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
) -> Result<$builder, Bolt12SemanticError> {
) -> Result<$builder, Bolt12CreationError> {
let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key;
let entropy = &*$self.entropy_source;
Expand All @@ -8884,7 +8902,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
let context = OffersContext::OutboundPayment { payment_id, nonce };
let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry))
.and_then(|paths| paths.into_iter().next().ok_or(()))
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
.map_err(|_| Bolt12CreationError::BlindedPathCreationFailed)?;

let builder = RefundBuilder::deriving_payer_id(
node_id, expanded_key, nonce, secp_ctx, amount_msats, payment_id
Expand All @@ -8900,7 +8918,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
.add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
)
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
.map_err(|_| Bolt12CreationError::DuplicatePaymentId)?;

Ok(builder.into())
}
Expand Down Expand Up @@ -8991,7 +9009,7 @@ where
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
payer_note: Option<String>, payment_id: PaymentId, retry_strategy: Retry,
max_total_routing_fee_msat: Option<u64>
) -> Result<(), Bolt12SemanticError> {
) -> Result<(), Bolt12CreationError> {
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;
Expand All @@ -9018,7 +9036,7 @@ where

let context = OffersContext::OutboundPayment { payment_id, nonce };
let reply_paths = self.create_blinded_paths(context)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
.map_err(|_| Bolt12CreationError::BlindedPathCreationFailed)?;

let total_liquidity: u64 = self.list_usable_channels().iter().map(|channel| channel.next_outbound_htlc_limit_msat).sum();
let total_amount_msats = match invoice_request.amount_msats() {
Expand All @@ -9032,7 +9050,7 @@ where
if let Some(amount) = total_amount_msats {
if amount > total_liquidity {
log_error!(self.logger, "Insufficient liquidity for payment with payment id: {}", payment_id);
return Err(Bolt12SemanticError::InsufficientLiquidity);
return Err(Bolt12CreationError::InsufficientLiquidity);
}
}

Expand All @@ -9043,7 +9061,7 @@ where
.add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, max_total_routing_fee_msat
)
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
.map_err(|_| Bolt12CreationError::DuplicatePaymentId)?;

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
if !offer.paths().is_empty() {
Expand All @@ -9070,7 +9088,7 @@ where
}
} else {
debug_assert!(false);
return Err(Bolt12SemanticError::MissingSigningPubkey);
return Err(Bolt12CreationError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
}

Ok(())
Expand Down Expand Up @@ -9100,7 +9118,7 @@ where
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn request_refund_payment(
&self, refund: &Refund
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
) -> Result<Bolt12Invoice, Bolt12CreationError> {
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;
Expand All @@ -9109,7 +9127,7 @@ where
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;

if refund.chain() != self.chain_hash {
return Err(Bolt12SemanticError::UnsupportedChain);
return Err(Bolt12CreationError::InvalidSemantics(Bolt12SemanticError::UnsupportedChain));
}

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
Expand All @@ -9120,7 +9138,7 @@ where
let payment_paths = self.create_blinded_payment_paths(
amount_msats, payment_secret, payment_context
)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
.map_err(|_| Bolt12CreationError::BlindedPathCreationFailed)?;

#[cfg(feature = "std")]
let builder = refund.respond_using_derived_keys(
Expand All @@ -9137,7 +9155,7 @@ where
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
let reply_paths = self.create_blinded_paths(OffersContext::Unknown {})
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
.map_err(|_| Bolt12CreationError::BlindedPathCreationFailed)?;

let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
if refund.paths().is_empty() {
Expand Down Expand Up @@ -9166,7 +9184,7 @@ where

Ok(invoice)
},
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
Err(()) => Err(Bolt12CreationError::InvalidSemantics(Bolt12SemanticError::InvalidAmount)),
}
}

Expand Down
24 changes: 12 additions & 12 deletions lightning/src/ln/offers_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use core::time::Duration;
use crate::blinded_path::{BlindedPath, IntroductionNode};
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentContext};
use crate::events::{Event, MessageSendEventsProvider, PaymentPurpose};
use crate::ln::channelmanager::{Bolt12PaymentError, MAX_SHORT_LIVED_RELATIVE_EXPIRY, PaymentId, RecentPaymentDetails, Retry, self};
use crate::ln::channelmanager::{Bolt12CreationError, Bolt12PaymentError, MAX_SHORT_LIVED_RELATIVE_EXPIRY, PaymentId, RecentPaymentDetails, Retry, self};
use crate::ln::functional_test_utils::*;
use crate::ln::msgs::{ChannelMessageHandler, Init, NodeAnnouncement, OnionMessage, OnionMessageHandler, RoutingMessageHandler, SocketAddress, UnsignedGossipMessage, UnsignedNodeAnnouncement};
use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS;
Expand Down Expand Up @@ -1600,7 +1600,7 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {
let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
match alice.node.create_offer_builder(Some(absolute_expiry)) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}

let mut args = ReconnectArgs::new(alice, bob);
Expand All @@ -1616,7 +1616,7 @@ fn fails_creating_or_paying_for_offer_without_connected_peers() {

match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}

assert!(nodes[0].node.list_recent_payments().is_empty());
Expand Down Expand Up @@ -1674,7 +1674,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None
) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}

let mut args = ReconnectArgs::new(charlie, david);
Expand All @@ -1688,7 +1688,7 @@ fn fails_creating_refund_or_sending_invoice_without_connected_peers() {

match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}

let mut args = ReconnectArgs::new(alice, bob);
Expand Down Expand Up @@ -1720,7 +1720,7 @@ fn fails_creating_invoice_request_for_unsupported_chain() {
let payment_id = PaymentId([1; 32]);
match bob.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
Err(e) => assert_eq!(e, Bolt12CreationError::InvalidSemantics(Bolt12SemanticError::UnsupportedChain)),
}
}

Expand All @@ -1747,7 +1747,7 @@ fn fails_sending_invoice_with_unsupported_chain_for_refund() {

match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
Err(e) => assert_eq!(e, Bolt12CreationError::InvalidSemantics(Bolt12SemanticError::UnsupportedChain)),
}
}

Expand Down Expand Up @@ -1780,7 +1780,7 @@ fn fails_creating_invoice_request_without_blinded_reply_path() {

match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}

assert!(nodes[0].node.list_recent_payments().is_empty());
Expand Down Expand Up @@ -1820,7 +1820,7 @@ fn fails_creating_invoice_request_with_duplicate_payment_id() {

match david.node.pay_for_offer(&offer, None, None, None, payment_id, Retry::Attempts(0), None) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
Err(e) => assert_eq!(e, Bolt12CreationError::DuplicatePaymentId),
}

expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
Expand Down Expand Up @@ -1848,7 +1848,7 @@ fn fails_creating_refund_with_duplicate_payment_id() {
10_000, absolute_expiry, payment_id, Retry::Attempts(0), None
) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
Err(e) => assert_eq!(e, Bolt12CreationError::DuplicatePaymentId),
}

expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
Expand Down Expand Up @@ -1970,7 +1970,7 @@ fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {

match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
Err(e) => assert_eq!(e, Bolt12CreationError::BlindedPathCreationFailed),
}
}

Expand Down Expand Up @@ -2093,7 +2093,7 @@ fn test_insufficient_liquidity_for_bolt12_offer() {
match result {
Ok(_) => panic!("Expected error with insufficient liquidity."),
Err(e) => {
assert_eq!(e, Bolt12SemanticError::InsufficientLiquidity);
assert_eq!(e, Bolt12CreationError::InsufficientLiquidity);
}
}
}
4 changes: 0 additions & 4 deletions lightning/src/offers/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,6 @@ pub enum Bolt12SemanticError {
MissingPayerMetadata,
/// A payer id was expected but was missing.
MissingPayerId,
/// The payment id for a refund or request is already in use.
DuplicatePaymentId,
/// Blinded paths were expected but were missing.
MissingPaths,
/// Blinded paths were provided but were not expected.
Expand All @@ -193,8 +191,6 @@ pub enum Bolt12SemanticError {
UnexpectedPaymentHash,
/// A signature was expected but was missing.
MissingSignature,
/// There is insufficient liquidity to complete the payment.
InsufficientLiquidity,
}

impl From<bech32::Error> for Bolt12ParseError {
Expand Down

0 comments on commit f2bc100

Please sign in to comment.