Skip to content

Commit

Permalink
Merge pull request #3202 from jkczyz/2024-07-blinded-path-auth-follow-up
Browse files Browse the repository at this point in the history
Follow-ups to #3139
  • Loading branch information
TheBlueMatt authored Aug 5, 2024
2 parents 8c1b3d1 + 8834336 commit 85e5e6a
Show file tree
Hide file tree
Showing 17 changed files with 299 additions and 205 deletions.
102 changes: 53 additions & 49 deletions fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,22 @@
use crate::utils::test_logger;
use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey};
use core::convert::TryFrom;
use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext};
use lightning::blinded_path::payment::{
Bolt12OfferContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay,
ReceiveTlvs,
};
use lightning::blinded_path::BlindedPath;
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
use lightning::ln::features::BlindedHopFeatures;
use lightning::ln::types::PaymentSecret;
use lightning::ln::PaymentHash;
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice_request::InvoiceRequest;
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
use lightning::offers::offer::OfferId;
use lightning::offers::parse::Bolt12SemanticError;
use lightning::sign::EntropySource;
use lightning::util::ser::Writeable;
use lightning::util::string::UntrustedString;

#[inline]
pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
Expand Down Expand Up @@ -76,57 +83,54 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
invoice_request: &InvoiceRequest, secp_ctx: &Secp256k1<T>,
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
let entropy_source = Randomness {};
let intermediate_nodes = [
[
ForwardNode { node_id: pubkey(43), short_channel_id: None },
ForwardNode { node_id: pubkey(44), short_channel_id: None },
],
[
ForwardNode { node_id: pubkey(45), short_channel_id: None },
ForwardNode { node_id: pubkey(46), short_channel_id: None },
],
];
let paths = vec![
BlindedPath::new_for_message(
&intermediate_nodes[0],
pubkey(42),
MessageContext::Offers(OffersContext::Unknown {}),
&entropy_source,
secp_ctx,
)
.unwrap(),
BlindedPath::new_for_message(
&intermediate_nodes[1],
pubkey(42),
MessageContext::Offers(OffersContext::Unknown {}),
&entropy_source,
secp_ctx,
)
.unwrap(),
];

let payinfo = vec![
BlindedPayInfo {
fee_base_msat: 1,
fee_proportional_millionths: 1_000,
cltv_expiry_delta: 42,
htlc_minimum_msat: 100,
htlc_maximum_msat: 1_000_000_000_000,
features: BlindedHopFeatures::empty(),
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: OfferId([42; 32]),
invoice_request: InvoiceRequestFields {
payer_id: invoice_request.payer_id(),
quantity: invoice_request.quantity(),
payer_note_truncated: invoice_request
.payer_note()
.map(|s| UntrustedString(s.to_string())),
},
});
let payee_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 1_000_000,
htlc_minimum_msat: 1,
},
BlindedPayInfo {
fee_base_msat: 1,
fee_proportional_millionths: 1_000,
cltv_expiry_delta: 42,
htlc_minimum_msat: 100,
htlc_maximum_msat: 1_000_000_000_000,
payment_context,
};
let intermediate_nodes = [ForwardNode {
tlvs: ForwardTlvs {
short_channel_id: 43,
payment_relay: PaymentRelay {
cltv_expiry_delta: 40,
fee_proportional_millionths: 1_000,
fee_base_msat: 1,
},
payment_constraints: PaymentConstraints {
max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40,
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
},
];
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
}];
let payment_path = BlindedPath::new_for_payment(
&intermediate_nodes,
pubkey(42),
payee_tlvs,
u64::MAX,
MIN_FINAL_CLTV_EXPIRY_DELTA,
&entropy_source,
secp_ctx,
)
.unwrap();

let payment_paths = payinfo.into_iter().zip(paths.into_iter()).collect();
let payment_hash = PaymentHash([42; 32]);
invoice_request.respond_with(payment_paths, payment_hash)?.build()
invoice_request.respond_with(vec![payment_path], payment_hash)?.build()
}

pub fn invoice_request_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
Expand Down
3 changes: 2 additions & 1 deletion fuzz/src/onion_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ struct TestOffersMessageHandler {}

impl OffersMessageHandler for TestOffersMessageHandler {
fn handle_message(
&self, _message: OffersMessage, _context: OffersContext, _responder: Option<Responder>,
&self, _message: OffersMessage, _context: Option<OffersContext>,
_responder: Option<Responder>,
) -> ResponseInstruction<OffersMessage> {
ResponseInstruction::NoResponse
}
Expand Down
89 changes: 41 additions & 48 deletions fuzz/src/refund_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
use crate::utils::test_logger;
use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey};
use core::convert::TryFrom;
use lightning::blinded_path::message::{ForwardNode, MessageContext, OffersContext};
use lightning::blinded_path::payment::{
Bolt12RefundContext, ForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext,
PaymentRelay, ReceiveTlvs,
};
use lightning::blinded_path::BlindedPath;
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
use lightning::ln::features::BlindedHopFeatures;
use lightning::ln::types::PaymentSecret;
use lightning::ln::PaymentHash;
use lightning::offers::invoice::{BlindedPayInfo, UnsignedBolt12Invoice};
use lightning::offers::invoice::UnsignedBolt12Invoice;
use lightning::offers::parse::Bolt12SemanticError;
use lightning::offers::refund::Refund;
use lightning::sign::EntropySource;
Expand Down Expand Up @@ -65,57 +70,45 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
refund: &Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1<T>,
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
let entropy_source = Randomness {};
let intermediate_nodes = [
[
ForwardNode { node_id: pubkey(43), short_channel_id: None },
ForwardNode { node_id: pubkey(44), short_channel_id: None },
],
[
ForwardNode { node_id: pubkey(45), short_channel_id: None },
ForwardNode { node_id: pubkey(46), short_channel_id: None },
],
];
let paths = vec![
BlindedPath::new_for_message(
&intermediate_nodes[0],
pubkey(42),
MessageContext::Offers(OffersContext::Unknown {}),
&entropy_source,
secp_ctx,
)
.unwrap(),
BlindedPath::new_for_message(
&intermediate_nodes[1],
pubkey(42),
MessageContext::Offers(OffersContext::Unknown {}),
&entropy_source,
secp_ctx,
)
.unwrap(),
];

let payinfo = vec![
BlindedPayInfo {
fee_base_msat: 1,
fee_proportional_millionths: 1_000,
cltv_expiry_delta: 42,
htlc_minimum_msat: 100,
htlc_maximum_msat: 1_000_000_000_000,
features: BlindedHopFeatures::empty(),
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
let payee_tlvs = ReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 1_000_000,
htlc_minimum_msat: 1,
},
BlindedPayInfo {
fee_base_msat: 1,
fee_proportional_millionths: 1_000,
cltv_expiry_delta: 42,
htlc_minimum_msat: 100,
htlc_maximum_msat: 1_000_000_000_000,
payment_context,
};
let intermediate_nodes = [ForwardNode {
tlvs: ForwardTlvs {
short_channel_id: 43,
payment_relay: PaymentRelay {
cltv_expiry_delta: 40,
fee_proportional_millionths: 1_000,
fee_base_msat: 1,
},
payment_constraints: PaymentConstraints {
max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40,
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),
},
];
node_id: pubkey(43),
htlc_maximum_msat: 1_000_000_000_000,
}];
let payment_path = BlindedPath::new_for_payment(
&intermediate_nodes,
pubkey(42),
payee_tlvs,
u64::MAX,
MIN_FINAL_CLTV_EXPIRY_DELTA,
&entropy_source,
secp_ctx,
)
.unwrap();

let payment_paths = payinfo.into_iter().zip(paths.into_iter()).collect();
let payment_hash = PaymentHash([42; 32]);
refund.respond_with(payment_paths, payment_hash, signing_pubkey)?.build()
refund.respond_with(vec![payment_path], payment_hash, signing_pubkey)?.build()
}

pub fn refund_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
Expand Down
27 changes: 18 additions & 9 deletions lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::blinded_path::utils;
use crate::io;
use crate::io::Cursor;
use crate::ln::channelmanager::PaymentId;
use crate::ln::onion_utils;
use crate::ln::{PaymentHash, onion_utils};
use crate::offers::nonce::Nonce;
use crate::onion_message::packet::ControlTlvs;
use crate::sign::{NodeSigner, Recipient};
Expand Down Expand Up @@ -108,11 +108,6 @@ pub enum MessageContext {
/// [`OffersMessage`]: crate::onion_message::offers::OffersMessage
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OffersContext {
/// Represents an unknown BOLT12 message context.
///
/// This variant is used when a message is sent without using a [`BlindedPath`] or over one
/// created prior to LDK version 0.0.124.
Unknown {},
/// Context used by a [`BlindedPath`] within an [`Offer`].
///
/// This variant is intended to be received when handling an [`InvoiceRequest`].
Expand Down Expand Up @@ -152,6 +147,18 @@ pub enum OffersContext {
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
nonce: Nonce,
},
/// Context used by a [`BlindedPath`] as a reply path for a [`Bolt12Invoice`].
///
/// This variant is intended to be received when handling an [`InvoiceError`].
///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
/// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
InboundPayment {
/// The same payment hash as [`Bolt12Invoice::payment_hash`].
///
/// [`Bolt12Invoice::payment_hash`]: crate::offers::invoice::Bolt12Invoice::payment_hash
payment_hash: PaymentHash,
},
}

impl_writeable_tlv_based_enum!(MessageContext,
Expand All @@ -160,14 +167,16 @@ impl_writeable_tlv_based_enum!(MessageContext,
);

impl_writeable_tlv_based_enum!(OffersContext,
(0, Unknown) => {},
(1, InvoiceRequest) => {
(0, InvoiceRequest) => {
(0, nonce, required),
},
(2, OutboundPayment) => {
(1, OutboundPayment) => {
(0, payment_id, required),
(1, nonce, required),
},
(2, InboundPayment) => {
(0, payment_hash, required),
},
);

/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
Expand Down
8 changes: 4 additions & 4 deletions lightning/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ pub enum Event {
/// The context of the [`BlindedPath`] used to send the invoice.
///
/// [`BlindedPath`]: crate::blinded_path::BlindedPath
context: OffersContext,
context: Option<OffersContext>,
/// A responder for replying with an [`InvoiceError`] if needed.
///
/// `None` if the invoice wasn't sent with a reply path.
Expand Down Expand Up @@ -1658,7 +1658,7 @@ impl Writeable for Event {
write_tlv_fields!(writer, {
(0, payment_id, required),
(2, invoice, required),
(4, context, required),
(4, context, option),
(6, responder, option),
});
},
Expand Down Expand Up @@ -2113,13 +2113,13 @@ impl MaybeReadable for Event {
_init_and_read_len_prefixed_tlv_fields!(reader, {
(0, payment_id, required),
(2, invoice, required),
(4, context, required),
(4, context, option),
(6, responder, option),
});
Ok(Some(Event::InvoiceReceived {
payment_id: payment_id.0.unwrap(),
invoice: invoice.0.unwrap(),
context: context.0.unwrap(),
context,
responder,
}))
};
Expand Down
Loading

0 comments on commit 85e5e6a

Please sign in to comment.