Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lightning-background-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ pub const NO_ONION_MESSENGER: Option<
OMH = lightning::ln::peer_handler::IgnoringMessageHandler,
APH = lightning::ln::peer_handler::IgnoringMessageHandler,
DRH = lightning::ln::peer_handler::IgnoringMessageHandler,
PNH = lightning::ln::peer_handler::IgnoringMessageHandler,
CMH = lightning::ln::peer_handler::IgnoringMessageHandler,
> + Send
+ Sync,
Expand Down Expand Up @@ -830,7 +831,7 @@ use futures_util::{dummy_waker, Joiner, OptionalSelector, Selector, SelectorOutp
/// # type NetworkGraph = lightning::routing::gossip::NetworkGraph<Arc<Logger>>;
/// # type P2PGossipSync<UL> = lightning::routing::gossip::P2PGossipSync<Arc<NetworkGraph>, Arc<UL>, Arc<Logger>>;
/// # type ChannelManager<B, F, FE> = lightning::ln::channelmanager::SimpleArcChannelManager<ChainMonitor<B, F, FE>, B, FE, Logger>;
/// # type OnionMessenger<B, F, FE> = lightning::onion_message::messenger::OnionMessenger<Arc<lightning::sign::KeysManager>, Arc<lightning::sign::KeysManager>, Arc<Logger>, Arc<ChannelManager<B, F, FE>>, Arc<lightning::onion_message::messenger::DefaultMessageRouter<Arc<NetworkGraph>, Arc<Logger>, Arc<lightning::sign::KeysManager>>>, Arc<ChannelManager<B, F, FE>>, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler>;
/// # type OnionMessenger<B, F, FE> = lightning::onion_message::messenger::OnionMessenger<Arc<lightning::sign::KeysManager>, Arc<lightning::sign::KeysManager>, Arc<Logger>, Arc<ChannelManager<B, F, FE>>, Arc<lightning::onion_message::messenger::DefaultMessageRouter<Arc<NetworkGraph>, Arc<Logger>, Arc<lightning::sign::KeysManager>>>, Arc<ChannelManager<B, F, FE>>, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler, lightning::ln::peer_handler::IgnoringMessageHandler>;
/// # type LiquidityManager<B, F, FE> = lightning_liquidity::LiquidityManager<Arc<lightning::sign::KeysManager>, Arc<lightning::sign::KeysManager>, Arc<ChannelManager<B, F, FE>>, Arc<Store>, Arc<DefaultTimeProvider>, Arc<B>>;
/// # type Scorer = RwLock<lightning::routing::scoring::ProbabilisticScorer<Arc<NetworkGraph>, Arc<Logger>>>;
/// # type PeerManager<B, F, FE, UL> = lightning::ln::peer_handler::SimpleArcPeerManager<SocketDescriptor, ChainMonitor<B, F, FE>, B, FE, Arc<UL>, Logger, F, StoreSync>;
Expand Down Expand Up @@ -2087,6 +2088,7 @@ mod tests {
Arc<ChannelManager>,
IgnoringMessageHandler,
IgnoringMessageHandler,
IgnoringMessageHandler,
>;

type LM = LiquidityManagerSync<
Expand Down Expand Up @@ -2512,6 +2514,7 @@ mod tests {
Arc::clone(&manager),
IgnoringMessageHandler {},
IgnoringMessageHandler {},
IgnoringMessageHandler {},
));
let wallet = Arc::new(TestWallet {});
let sweeper = Arc::new(OutputSweeperSync::new(
Expand Down
4 changes: 4 additions & 0 deletions lightning-dns-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ mod test {
IgnoringMessageHandler {},
Arc::clone(&resolver),
IgnoringMessageHandler {},
IgnoringMessageHandler {},
),
resolver_keys.get_node_id(Recipient::Node).unwrap(),
)
Expand Down Expand Up @@ -292,6 +293,7 @@ mod test {
IgnoringMessageHandler {},
Arc::clone(&payer),
IgnoringMessageHandler {},
IgnoringMessageHandler {},
));

let init_msg = get_om_init();
Expand Down Expand Up @@ -363,6 +365,7 @@ mod test {
IgnoringMessageHandler {},
Arc::clone(&resolver),
IgnoringMessageHandler {},
IgnoringMessageHandler {},
);
let resolver_id = resolver_keys.get_node_id(Recipient::Node).unwrap();

Expand Down Expand Up @@ -390,6 +393,7 @@ mod test {
IgnoringMessageHandler {},
Arc::clone(&payer),
IgnoringMessageHandler {},
IgnoringMessageHandler {},
));

let init_msg = get_om_init();
Expand Down
20 changes: 19 additions & 1 deletion lightning-types/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
//! (see [BOLT PR #1160](https://github.com/lightning/bolts/pull/1160) for more information).
//! - `HtlcHold` - requires/supports holding HTLCs and forwarding on receipt of an onion message
//! (see [BOLT-2](https://github.com/lightning/bolts/pull/989/files) for more information).
//! - `PaymentNotifications` - supports delivering payment notifications for point-of-sale offers
//! (see [bLIP 56](https://github.com/lightning/blips/pull/56) for more information).
//!
//! LDK knows about the following features, but does not support them:
//! - `AnchorsNonzeroFeeHtlcTx` - the initial version of anchor outputs, which was later found to be
Expand Down Expand Up @@ -221,7 +223,12 @@ mod sealed {
// Byte 7
Trampoline,
]);
define_context!(OfferContext, []);
define_context!(OfferContext, [
// Byte 0 - 32
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
// Byte 33
PaymentNotifications,
]);
define_context!(InvoiceRequestContext, []);
define_context!(Bolt12InvoiceContext, [
// Byte 0
Expand Down Expand Up @@ -728,6 +735,17 @@ mod sealed {
supports_dns_resolution,
requires_dns_resolution
);
define_feature!(
265,
PaymentNotifications,
[OfferContext],
"Feature flags for point-of-sale payment notifications.",
set_payment_notifications_optional,
set_payment_notifications_required,
clear_payment_notifications,
supports_payment_notifications,
requires_payment_notifications
);

// Note: update the module-level docs when a new feature bit is added!

Expand Down
76 changes: 76 additions & 0 deletions lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ pub enum MessageContext {
///
/// [`CustomOnionMessageHandler::CustomMessage`]: crate::onion_message::messenger::CustomOnionMessageHandler::CustomMessage
Custom(Vec<u8>),
/// Context specific to a [`PosNotificationMessage`].
///
/// [`PosNotificationMessage`]: crate::onion_message::pos_notification::PosNotificationMessage
PosNotification(PosNotificationContext),
}

/// Contains data specific to an [`OffersMessage`].
Expand Down Expand Up @@ -509,6 +513,21 @@ pub enum OffersContext {
/// [`Bolt12Invoice::payment_hash`]: crate::offers::invoice::Bolt12Invoice::payment_hash
payment_hash: PaymentHash,
},
/// Context used by a [`BlindedMessagePath`] within an [`Offer`] template handed to a
/// point-of-sale device for per-order offer construction.
///
/// This variant is intended to be received when handling an [`InvoiceRequest`] for an offer the
/// point-of-sale device derived from the template. Since the device modifies the offer's TLV
/// records, the offer cannot be authenticated via its metadata; instead, the signing keys are
/// re-derived from the nonce alone and matched against the offer's signing pubkey.
///
/// [`Offer`]: crate::offers::offer::Offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
DelegatedInvoiceRequest {
/// A nonce used for deriving the signing keys of the offer template independently of its TLV
/// records.
nonce: Nonce,
},
}

/// Contains data specific to an [`AsyncPaymentsMessage`].
Expand Down Expand Up @@ -665,6 +684,7 @@ impl_ser_tlv_based_enum!(MessageContext,
{1, Custom} => (),
{2, AsyncPayments} => (),
{3, DNSResolver} => (),
{4, PosNotification} => (),
);

// Note: Several TLV fields (`nonce`, `hmac`, etc.) were removed in LDK v0.2 following the
Expand Down Expand Up @@ -692,6 +712,9 @@ impl_ser_tlv_based_enum!(OffersContext,
(0, payment_id, required),
(1, nonce, required),
},
(5, DelegatedInvoiceRequest) => {
(0, nonce, required),
},
);

impl_ser_tlv_based_enum!(AsyncPaymentsContext,
Expand Down Expand Up @@ -741,6 +764,59 @@ impl_ser_tlv_based!(DNSResolverContext, {
(0, nonce, required),
});

/// Contains data specific to a [`PosNotificationMessage`].
///
/// [`PosNotificationMessage`]: crate::onion_message::pos_notification::PosNotificationMessage
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PosNotificationContext {
/// Context used by a point-of-sale device in a per-order offer's `notification_path`.
///
/// This variant is intended to be received when handling a `payment_notification` from the
/// merchant or a `payment_proof` from the customer. It carries the full order state so that
/// the device does not need to persist outstanding orders: the path-level authentication of
/// the blinded path guarantees the context was created by this device, and matching
/// [`Self::InboundOrder::order_id`] against the `order_id` relayed in the notification
/// authenticates the notification as merchant-originated.
InboundOrder {
/// The per-order secret also sealed into the offer's `payment_token`. Only the merchant
/// can recover it from the token, so a notification relaying it must have come from the
/// merchant.
order_id: Vec<u8>,

/// The amount in millisatoshis set on the per-order offer. A notification for a smaller
/// amount must be rejected.
amount_msats: u64,

/// The description set on the per-order offer, if any.
description: Option<String>,

/// The time as duration since the Unix epoch at which the order expires and notifications
/// for it should be rejected. Set from the per-order offer's `offer_absolute_expiry`.
order_absolute_expiry: Option<Duration>,
},
/// Context used by a merchant in the reply path of a `payment_notification`.
///
/// This variant is intended to be received when handling a `notification_ack` or
/// `notification_nack` from the point-of-sale device, and identifies the pending notification
/// being acknowledged.
OutboundNotification {
/// The payment hash of the claimed payment the notification was sent for.
payment_hash: PaymentHash,
},
}

impl_ser_tlv_based_enum!(PosNotificationContext,
(0, InboundOrder) => {
(0, order_id, required_vec),
(2, amount_msats, required),
(3, description, option),
(4, order_absolute_expiry, option),
},
(1, OutboundNotification) => {
(0, payment_hash, required),
},
);

/// Represents the padding round off size (in bytes) that is used
/// to pad message blinded path's [`BlindedHop`]
pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
Expand Down
122 changes: 122 additions & 0 deletions lightning/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,60 @@ pub enum Event {
/// [`ChannelManager::funding_transaction_signed`]: crate::ln::channelmanager::ChannelManager::funding_transaction_signed
unsigned_transaction: Transaction,
},
/// A merchant's `payment_notification` for a per-order offer constructed by this node as a
/// point-of-sale device was received and authenticated, meaning the merchant claimed the
/// payment for the order. A `notification_ack` was sent in response.
///
/// The notification was authenticated by matching the relayed `order_id` against the one in
/// the offer's notification path context, and the preimage and amount were verified. Handle
/// duplicates idempotently: the merchant retries notifications until acknowledged, so a
/// second event for an already-confirmed order may occur and must not record the payment
/// twice.
///
/// See [bLIP 56](https://github.com/lightning/blips/pull/56) for more information.
///
/// # Failure Behavior and Persistence
/// This event will eventually be replayed after failures-to-handle (i.e., the event handler
/// returning `Err(ReplayEvent ())`) and will be persisted across restarts.
PaymentNotificationReceived {
/// The per-order secret identifying the order, as generated when constructing the
/// per-order offer.
order_id: Vec<u8>,
/// The amount claimed by the merchant, in millisatoshis. At least the order amount.
amount_msats: u64,
/// The payment hash of the claimed payment.
payment_hash: PaymentHash,
/// The payment preimage released by the merchant when claiming the payment.
payment_preimage: PaymentPreimage,
/// The description set on the per-order offer, if any.
description: Option<String>,
},
/// A customer's `payment_proof` for a per-order offer constructed by this node as a
/// point-of-sale device was received over the offer's notification path.
///
/// The proof is a serialized BOLT 12 payer proof, as defined in
/// [bolts#1295](https://github.com/lightning/bolts/pull/1295). It is provided as opaque bytes
/// and has NOT been verified; verifying it per the bolts#1295 reader requirements, including
/// that the mirrored `payment_token` matches the one issued for this order, is the handler's
/// responsibility.
///
/// See [bLIP 56](https://github.com/lightning/blips/pull/56) for more information.
///
/// # Failure Behavior and Persistence
/// This event will eventually be replayed after failures-to-handle (i.e., the event handler
/// returning `Err(ReplayEvent ())`) and will be persisted across restarts.
PaymentProofReceived {
/// The per-order secret identifying the order, as generated when constructing the
/// per-order offer.
order_id: Vec<u8>,
/// The serialized, unverified BOLT 12 payer proof.
proof: Vec<u8>,
/// The amount in millisatoshis set on the per-order offer, against which the proof's
/// `invoice_amount` should be checked.
amount_msats: u64,
/// The description set on the per-order offer, if any.
description: Option<String>,
},
}

impl Writeable for Event {
Expand Down Expand Up @@ -2522,6 +2576,36 @@ impl Writeable for Event {
(13, contribution, option),
});
},
&Event::PaymentNotificationReceived {
ref order_id,
ref amount_msats,
ref payment_hash,
ref payment_preimage,
ref description,
} => {
53u8.write(writer)?;
write_tlv_fields!(writer, {
(1, order_id, required_vec),
(3, amount_msats, required),
(5, payment_hash, required),
(7, payment_preimage, required),
(9, description, option),
});
},
&Event::PaymentProofReceived {
ref order_id,
ref proof,
ref amount_msats,
ref description,
} => {
55u8.write(writer)?;
write_tlv_fields!(writer, {
(1, order_id, required_vec),
(3, proof, required_vec),
(5, amount_msats, required),
(7, description, option),
});
},
// Note that, going forward, all new events must only write data inside of
// `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write
// data via `write_tlv_fields`.
Expand Down Expand Up @@ -3176,6 +3260,44 @@ impl MaybeReadable for Event {
};
f()
},
53u8 => {
let mut f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(1, order_id, required_vec),
(3, amount_msats, required),
(5, payment_hash, required),
(7, payment_preimage, required),
(9, description, option),
});

Ok(Some(Event::PaymentNotificationReceived {
order_id,
amount_msats: amount_msats.0.unwrap(),
payment_hash: payment_hash.0.unwrap(),
payment_preimage: payment_preimage.0.unwrap(),
description,
}))
};
f()
},
55u8 => {
let mut f = || {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(1, order_id, required_vec),
(3, proof, required_vec),
(5, amount_msats, required),
(7, description, option),
});

Ok(Some(Event::PaymentProofReceived {
order_id,
proof,
amount_msats: amount_msats.0.unwrap(),
description,
}))
};
f()
},
// Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
// Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt
// reads.
Expand Down
Loading