#![cfg_attr(rustfmt, rustfmt_skip)]
use alloc::collections::BTreeMap;
use bitcoin::network::Network;
use bitcoin::secp256k1::{PublicKey, Secp256k1};
use core::time::Duration;
use crate::blinded_path::IntroductionNode;
use crate::blinded_path::message::BlindedMessagePath;
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, DummyTlvs, PaymentContext};
use crate::blinded_path::message::{MessageContext, OffersContext};
use crate::events::{ClosureReason, Event, HTLCHandlingFailureType, PaidBolt12Invoice, PaymentFailureReason, PaymentPurpose};
use crate::ln::channelmanager::{PaymentId, RecentPaymentDetails, self};
use crate::ln::outbound_payment::{Bolt12PaymentError, RecipientOnionFields, Retry};
use crate::types::features::Bolt12InvoiceFeatures;
use crate::ln::functional_test_utils::*;
use crate::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init, OnionMessage, OnionMessageHandler};
use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS;
use crate::offers::invoice::Bolt12Invoice;
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields, InvoiceRequestVerifiedFromOffer};
use crate::offers::nonce::Nonce;
use crate::offers::offer::OfferBuilder;
use crate::offers::parse::Bolt12SemanticError;
use crate::offers::payer_proof::PayerProof;
use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, MessageSendInstructions, NodeIdMessageRouter, NullMessageRouter, PeeledOnion, DUMMY_HOPS_PATH_LENGTH, QR_CODED_DUMMY_HOPS_PATH_LENGTH};
use crate::onion_message::offers::OffersMessage;
use crate::routing::router::{DEFAULT_PAYMENT_DUMMY_HOPS, PaymentParameters, RouteParameters, RouteParametersConfig};
use crate::sign::NodeSigner;
use crate::util::ser::{MaybeReadable, Writeable};
const MAX_SHORT_LIVED_RELATIVE_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
use crate::prelude::*;
macro_rules! expect_recent_payment {
($node: expr, $payment_state: path, $payment_id: expr) => {{
let mut found_payment = false;
for payment in $node.node.list_recent_payments().iter() {
match payment {
$payment_state { payment_id: actual_payment_id, .. } => {
if $payment_id == *actual_payment_id {
found_payment = true;
break;
}
},
_ => {},
}
}
assert!(found_payment);
}}
}
fn connect_peers<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>) {
let node_id_a = node_a.node.get_our_node_id();
let node_id_b = node_b.node.get_our_node_id();
let init_a = Init {
features: node_a.init_features(node_id_b),
networks: None,
remote_network_address: None,
};
let init_b = Init {
features: node_b.init_features(node_id_a),
networks: None,
remote_network_address: None,
};
node_a.node.peer_connected(node_id_b, &init_b, true).unwrap();
node_b.node.peer_connected(node_id_a, &init_a, false).unwrap();
node_a.onion_messenger.peer_connected(node_id_b, &init_b, true).unwrap();
node_b.onion_messenger.peer_connected(node_id_a, &init_a, false).unwrap();
}
fn disconnect_peers<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, peers: &[&Node<'a, 'b, 'c>]) {
for node_b in peers {
node_a.node.peer_disconnected(node_b.node.get_our_node_id());
node_b.node.peer_disconnected(node_a.node.get_our_node_id());
node_a.onion_messenger.peer_disconnected(node_b.node.get_our_node_id());
node_b.onion_messenger.peer_disconnected(node_a.node.get_our_node_id());
}
}
fn resolve_introduction_node<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, path: &BlindedMessagePath) -> PublicKey {
path.public_introduction_node_id(&node.network_graph.read_only())
.and_then(|node_id| node_id.as_pubkey().ok())
.unwrap()
}
fn check_compact_path_introduction_node<'a, 'b, 'c>(
path: &BlindedMessagePath,
lookup_node: &Node<'a, 'b, 'c>,
expected_introduction_node: PublicKey,
) -> bool {
let introduction_node_id = resolve_introduction_node(lookup_node, path);
introduction_node_id == expected_introduction_node
&& matches!(path.introduction_node(), IntroductionNode::DirectedShortChannelId(..))
}
fn check_dummy_hopped_path_length<'a, 'b, 'c>(
path: &BlindedMessagePath,
lookup_node: &Node<'a, 'b, 'c>,
expected_introduction_node: PublicKey,
expected_path_length: usize,
) -> bool {
let introduction_node_id = resolve_introduction_node(lookup_node, path);
let first_hop_len = path.blinded_hops().first().unwrap().encrypted_payload.len();
let hops = path.blinded_hops();
introduction_node_id == expected_introduction_node
&& hops.len() == expected_path_length
&& hops.iter().take(hops.len() - 1).all(|hop| hop.encrypted_payload.len() == first_hop_len)
}
fn route_bolt12_payment<'a, 'b, 'c>(
node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], invoice: &Bolt12Invoice
) {
check_added_monitors(node, 1);
let mut events = node.node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let ev = remove_first_msg_event_to_node(&path[0].node.get_our_node_id(), &mut events);
let amount_msats = invoice.amount_msats();
let payment_hash = invoice.payment_hash();
let args = PassAlongPathArgs::new(node, path, amount_msats, payment_hash, ev)
.without_clearing_recipient_events()
.with_dummy_tlvs(&[DummyTlvs::default(); DEFAULT_PAYMENT_DUMMY_HOPS]);
do_pass_along_path(args);
}
fn claim_bolt12_payment<'a, 'b, 'c>(
node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], expected_payment_context: PaymentContext, invoice: &Bolt12Invoice
) {
claim_bolt12_payment_with_extra_fees(
node,
path,
expected_payment_context,
invoice,
None,
)
}
fn claim_bolt12_payment_with_extra_fees<'a, 'b, 'c>(
node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], expected_payment_context: PaymentContext, invoice: &Bolt12Invoice,
expected_extra_fees_msat: Option<u64>,
) {
let recipient = path.last().expect("Empty path?");
let payment_purpose = match get_event!(recipient, Event::PaymentClaimable) {
Event::PaymentClaimable { purpose, .. } => purpose,
_ => panic!("No Event::PaymentClaimable"),
};
let payment_preimage = match payment_purpose.preimage() {
Some(preimage) => preimage,
None => panic!("No preimage in Event::PaymentClaimable"),
};
let context = match payment_purpose {
PaymentPurpose::Bolt12OfferPayment { payment_context, .. } =>
PaymentContext::Bolt12Offer(payment_context),
PaymentPurpose::Bolt12RefundPayment { payment_context, .. } =>
PaymentContext::Bolt12Refund(payment_context),
_ => panic!("Unexpected payment purpose: {:?}", payment_purpose),
};
assert_eq!(context, expected_payment_context);
let expected_paths = [path];
let mut args = ClaimAlongRouteArgs::new(
node,
&expected_paths,
payment_preimage,
);
if let Some(extra) = expected_extra_fees_msat {
args = args.with_expected_extra_total_fees_msat(extra);
}
let (inv, _) = claim_payment_along_route(args);
assert_eq!(inv, Some(PaidBolt12Invoice::Bolt12Invoice(invoice.clone())));
}
fn extract_offer_nonce<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> Nonce {
match node.onion_messenger.peel_onion_message(message) {
Ok(PeeledOnion::Offers(_, Some(OffersContext::InvoiceRequest { nonce, payment_metadata: _ }), _)) => nonce,
Ok(PeeledOnion::Offers(_, context, _)) => panic!("Unexpected onion message context: {:?}", context),
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
Ok(_) => panic!("Unexpected onion message"),
Err(e) => panic!("Failed to process onion message {:?}", e),
}
}
fn extract_payer_context<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> PaymentId {
match node.onion_messenger.peel_onion_message(message) {
Ok(PeeledOnion::Offers(_, Some(OffersContext::OutboundPaymentForOffer { payment_id, .. }), _)) => payment_id,
Ok(PeeledOnion::Offers(_, context, _)) => panic!("Expected OutboundPaymentForOffer context, got: {:?}", context),
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
Ok(_) => panic!("Unexpected onion message"),
Err(e) => panic!("Failed to process onion message {:?}", e),
}
}
pub(super) fn extract_invoice_request<'a, 'b, 'c>(
node: &Node<'a, 'b, 'c>, message: &OnionMessage
) -> (InvoiceRequest, BlindedMessagePath) {
match node.onion_messenger.peel_onion_message(message) {
Ok(PeeledOnion::Offers(message, _, reply_path)) => match message {
OffersMessage::InvoiceRequest(invoice_request) => (invoice_request, reply_path.unwrap()),
OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),
OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice),
OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error),
},
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
Ok(_) => panic!("Unexpected onion message"),
Err(e) => panic!("Failed to process onion message {:?}", e),
}
}
fn extract_invoice<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> (Bolt12Invoice, BlindedMessagePath) {
match node.onion_messenger.peel_onion_message(message) {
Ok(PeeledOnion::Offers(message, _, reply_path)) => match message {
OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request),
OffersMessage::Invoice(invoice) => (invoice, reply_path.unwrap()),
OffersMessage::StaticInvoice(invoice) => panic!("Unexpected static invoice: {:?}", invoice),
OffersMessage::InvoiceError(error) => panic!("Unexpected invoice_error: {:?}", error),
},
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
Ok(_) => panic!("Unexpected onion message"),
Err(e) => panic!("Failed to process onion message {:?}", e),
}
}
fn extract_invoice_error<'a, 'b, 'c>(
node: &Node<'a, 'b, 'c>, message: &OnionMessage
) -> InvoiceError {
match node.onion_messenger.peel_onion_message(message) {
Ok(PeeledOnion::Offers(message, _, _)) => match message {
OffersMessage::InvoiceRequest(invoice_request) => panic!("Unexpected invoice_request: {:?}", invoice_request),
OffersMessage::Invoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),
OffersMessage::StaticInvoice(invoice) => panic!("Unexpected invoice: {:?}", invoice),
OffersMessage::InvoiceError(error) => error,
},
Ok(PeeledOnion::Forward(_, _)) => panic!("Unexpected onion message forward"),
Ok(_) => panic!("Unexpected onion message"),
Err(e) => panic!("Failed to process onion message {:?}", e),
}
}
#[test]
fn create_offer_with_no_blinded_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let router = NullMessageRouter {};
let offer = alice.node
.create_offer_builder_using_router(&router).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_eq!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(offer.paths().is_empty());
}
#[test]
fn create_refund_with_no_blinded_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let router = NullMessageRouter {};
let refund = alice.node
.create_refund_builder_using_router(&router, 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_eq!(refund.amount_msats(), 10_000_000);
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
assert_eq!(refund.payer_signing_pubkey(), alice_id);
assert!(refund.paths().is_empty());
}
#[test]
fn check_dummy_hop_pattern_in_offer() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let default_router = DefaultMessageRouter::new(alice.network_graph, alice.keys_manager);
let compact_offer = alice.node
.create_offer_builder_using_router(&default_router).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert!(!compact_offer.paths().is_empty());
for path in compact_offer.paths() {
assert_eq!(
path.blinded_hops().len(), QR_CODED_DUMMY_HOPS_PATH_LENGTH,
"Compact offer paths are padded to QR_CODED_DUMMY_HOPS_PATH_LENGTH"
);
}
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&compact_offer, None, payment_id, Default::default()).unwrap();
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
assert!(check_dummy_hopped_path_length(&reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH));
let node_id_router = NodeIdMessageRouter::new(alice.network_graph, alice.keys_manager);
let padded_offer = alice.node
.create_offer_builder_using_router(&node_id_router).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert!(!padded_offer.paths().is_empty());
assert!(padded_offer.paths().iter().all(|path| path.blinded_hops().len() == QR_CODED_DUMMY_HOPS_PATH_LENGTH));
let payment_id = PaymentId([2; 32]);
bob.node.pay_for_offer(&padded_offer, None, payment_id, Default::default()).unwrap();
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
assert!(check_dummy_hopped_path_length(&reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH));
}
#[test]
fn creates_short_lived_offer() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let offer = alice.node
.create_offer_builder().unwrap()
.build().unwrap();
assert!(!offer.paths().is_empty());
for path in offer.paths() {
let introduction_node_id = resolve_introduction_node(bob, &path);
assert_eq!(introduction_node_id, alice_id);
assert!(matches!(path.introduction_node(), &IntroductionNode::DirectedShortChannelId(..)));
}
}
#[test]
fn creates_long_lived_offer() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let router = NodeIdMessageRouter::new(alice.network_graph, alice.keys_manager);
let offer = alice.node
.create_offer_builder_using_router(&router)
.unwrap()
.build().unwrap();
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
}
#[test]
fn creates_short_lived_refund() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let payment_id = PaymentId([1; 32]);
let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
assert!(!refund.paths().is_empty());
for path in refund.paths() {
let introduction_node_id = resolve_introduction_node(alice, &path);
assert_eq!(introduction_node_id, bob_id);
assert!(matches!(path.introduction_node(), &IntroductionNode::DirectedShortChannelId(..)));
}
}
#[test]
fn creates_long_lived_refund() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let absolute_expiry = bob.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY
+ Duration::from_secs(1);
let payment_id = PaymentId([1; 32]);
let router = NodeIdMessageRouter::new(bob.network_graph, bob.keys_manager);
let refund = bob.node
.create_refund_builder_using_router(&router, 10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
}
#[test]
fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), david_id);
assert!(check_dummy_hopped_path_length(&reply_path, bob, charlie_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let (invoice, reply_path) = extract_invoice(david, &onion_message);
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
assert!(
check_dummy_hopped_path_length(&reply_path, david, bob_id, DUMMY_HOPS_PATH_LENGTH) ||
check_dummy_hopped_path_length(&reply_path, david, charlie_id, DUMMY_HOPS_PATH_LENGTH)
);
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice);
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn creates_and_pays_for_refund_using_two_hop_blinded_path() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_eq!(refund.amount_msats(), 10_000_000);
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
assert_ne!(refund.payer_signing_pubkey(), david_id);
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert!(check_compact_path_introduction_node(&path, david, charlie_id));
}
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext { payment_metadata: None });
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
connect_peers(alice, charlie);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let (invoice, reply_path) = extract_invoice(david, &onion_message);
assert_eq!(invoice, expected_invoice);
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
assert!(check_dummy_hopped_path_length(&reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH));
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice);
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, bob, alice_id));
}
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
assert!(check_dummy_hopped_path_length(&reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, reply_path) = extract_invoice(bob, &onion_message);
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
assert!(check_dummy_hopped_path_length(&reply_path, bob, alice_id, DUMMY_HOPS_PATH_LENGTH));
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn router_modifies_payment_metadata_in_blinded_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let mut expected_metadata = BTreeMap::new();
expected_metadata.insert(0u64, vec![1, 2, 3, 4]);
expected_metadata.insert(7u64, vec![0xab, 0xcd]);
alice.router.set_next_payment_context_metadata(expected_metadata.clone());
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(alice, &onion_message);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(bob, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: Some(expected_metadata),
});
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn pays_for_offer_with_payment_metadata_in_invoice_request_context() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let mut expected_metadata = BTreeMap::new();
expected_metadata.insert(0u64, vec![1, 2, 3, 4]);
expected_metadata.insert(7u64, vec![0xab, 0xcd]);
let secp_ctx = Secp256k1::new();
let nonce = Nonce::from_entropy_source(alice.keys_manager);
let context = MessageContext::Offers(OffersContext::InvoiceRequest {
nonce,
payment_metadata: Some(expected_metadata.clone()),
});
let paths = alice.message_router.create_blinded_paths(
alice_id,
alice.keys_manager.get_receive_auth_key(),
context,
alice.node.test_get_peers_for_blinded_path(),
&secp_ctx,
).unwrap();
assert!(!paths.is_empty());
let expanded_key = alice.keys_manager.get_expanded_key();
let mut builder = OfferBuilder::deriving_signing_pubkey(alice_id, &expanded_key, nonce, &secp_ctx)
.chain(Network::Testnet)
.amount_msats(10_000_000);
for path in paths {
builder = builder.path(path);
}
let offer = builder.build().unwrap();
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(alice, &onion_message);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(bob, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: Some(expected_metadata),
});
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn creates_and_pays_for_refund_using_one_hop_blinded_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_eq!(refund.amount_msats(), 10_000_000);
assert_eq!(refund.absolute_expiry(), Some(absolute_expiry));
assert_ne!(refund.payer_signing_pubkey(), bob_id);
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext { payment_metadata: None });
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, reply_path) = extract_invoice(bob, &onion_message);
assert_eq!(invoice, expected_invoice);
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
assert!(check_dummy_hopped_path_length(&reply_path, bob, alice_id, DUMMY_HOPS_PATH_LENGTH));
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn pays_for_offer_without_blinded_paths() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.clear_paths()
.amount_msats(10_000_000)
.build().unwrap();
assert_eq!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(offer.paths().is_empty());
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(bob, &onion_message);
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn pays_for_refund_without_blinded_paths() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.clear_paths()
.build().unwrap();
assert_eq!(refund.payer_signing_pubkey(), bob_id);
assert!(refund.paths().is_empty());
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext { payment_metadata: None });
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(bob, &onion_message);
assert_eq!(invoice, expected_invoice);
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn send_invoice_requests_with_distinct_reply_path() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(7);
let node_cfgs = create_node_cfgs(7, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
7, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None, None]
);
let nodes = create_network(7, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 3, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 4, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 5, 6, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
let frank_id = nodes[6].node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5], &nodes[6]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (_, reply_path) = extract_invoice_request(alice, &onion_message);
assert!(check_dummy_hopped_path_length(&reply_path, alice, charlie_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (_, reply_path) = extract_invoice_request(alice, &onion_message);
assert!(check_dummy_hopped_path_length(&reply_path, alice, frank_id, DUMMY_HOPS_PATH_LENGTH));
}
#[test]
fn send_invoice_for_refund_with_distinct_reply_path() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(7);
let node_cfgs = create_node_cfgs(7, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
7, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None, None]
);
let nodes = create_network(7, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 3, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 4, 6, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 5, 6, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5], &nodes[6]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = alice.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), alice_id);
for path in refund.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
expect_recent_payment!(alice, RecentPaymentDetails::AwaitingInvoice, payment_id);
let _expected_invoice = david.node.request_refund_payment(&refund).unwrap();
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
let (_, reply_path) = extract_invoice(alice, &onion_message);
assert!(check_dummy_hopped_path_length(&reply_path, alice, charlie_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
let (_, reply_path) = extract_invoice(alice, &onion_message);
assert!(check_dummy_hopped_path_length(&reply_path, alice, nodes[6].node.get_our_node_id(), DUMMY_HOPS_PATH_LENGTH));
}
#[test]
fn creates_and_pays_for_offer_with_retry() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, bob, alice_id));
}
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let _lost_onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
assert!(bob.onion_messenger.next_onion_message_for_peer(alice_id).is_none());
bob.node.message_received();
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
assert!(check_dummy_hopped_path_length(&reply_path, alice, bob_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
bob.node.message_received();
assert!(bob.onion_messenger.next_onion_message_for_peer(alice_id).is_none());
let (invoice, _) = extract_invoice(bob, &onion_message);
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn pays_bolt12_invoice_asynchronously() {
let mut manually_pay_cfg = test_default_channel_config();
manually_pay_cfg.manually_handle_bolt12_invoices = true;
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_pay_cfg)]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let mut events = bob.node.get_and_clear_pending_events();
assert_eq!(events.len(), 1);
let (invoice, context) = match events.pop().unwrap() {
Event::InvoiceReceived { payment_id: actual_payment_id, invoice, context, .. } => {
assert_eq!(actual_payment_id, payment_id);
(invoice, context)
},
_ => panic!("No Event::InvoiceReceived"),
};
assert_eq!(invoice.amount_msats(), 10_000_000);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
assert!(bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()).is_ok());
assert_eq!(
bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()),
Err(Bolt12PaymentError::DuplicateInvoice),
);
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
assert_eq!(
bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()),
Err(Bolt12PaymentError::DuplicateInvoice),
);
for _ in 0..=IDEMPOTENCY_TIMEOUT_TICKS {
bob.node.timer_tick_occurred();
}
assert_eq!(
bob.node.send_payment_for_bolt12_invoice(&invoice, context.as_ref()),
Err(Bolt12PaymentError::UnexpectedInvoice),
);
}
#[test]
fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(alice_id));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, reply_path) = extract_invoice(bob, &onion_message);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
assert_eq!(reply_path.introduction_node(), &IntroductionNode::NodeId(bob_id));
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment_with_extra_fees(bob, &[alice], payment_context, &invoice, Some(1000));
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1];
let bob_id = bob.node.get_our_node_id();
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), bob_id);
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
}
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
let (invoice, _reply_path) = extract_invoice(bob, &onion_message);
assert_eq!(invoice, expected_invoice);
assert_ne!(invoice.signing_pubkey(), alice_id);
assert!(!invoice.payment_paths().is_empty());
for path in invoice.payment_paths() {
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
}
}
#[test]
fn fails_authentication_when_handling_invoice_request() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_eq!(offer.metadata(), None);
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
let invalid_path = alice.node
.create_offer_builder()
.unwrap()
.build().unwrap()
.paths().first().unwrap()
.clone();
assert!(check_compact_path_introduction_node(&invalid_path, alice, bob_id));
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
connect_peers(david, alice);
match &mut david.node.flow.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
*destination = Destination::Node(alice_id),
_ => panic!(),
}
let onion_message = david.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(david_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), david_id);
assert!(check_dummy_hopped_path_length(&reply_path, david, charlie_id, DUMMY_HOPS_PATH_LENGTH));
assert_eq!(alice.onion_messenger.next_onion_message_for_peer(charlie_id), None);
david.node.abandon_payment(payment_id);
get_event!(david, Event::PaymentFailed);
let payment_id = PaymentId([2; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
match &mut david.node.flow.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
*destination = Destination::BlindedPath(invalid_path),
_ => panic!(),
}
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), david_id);
assert!(check_dummy_hopped_path_length(&reply_path, david, charlie_id, DUMMY_HOPS_PATH_LENGTH));
assert_eq!(alice.onion_messenger.next_onion_message_for_peer(charlie_id), None);
}
#[test]
fn fails_authentication_when_handling_invoice_for_offer() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder()
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert!(check_compact_path_introduction_node(&path, alice, bob_id));
}
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
david.node.abandon_payment(payment_id);
get_event!(david, Event::PaymentFailed);
let invalid_reply_path = {
let mut pending_offers_messages = david.node.flow.pending_offers_messages.lock().unwrap();
let pending_invoice_request = pending_offers_messages.pop().unwrap();
pending_offers_messages.clear();
match pending_invoice_request.1 {
MessageSendInstructions::WithSpecifiedReplyPath { reply_path, .. } => reply_path,
_ => panic!(),
}
};
let payment_id = PaymentId([2; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
{
let mut pending_offers_messages = david.node.flow.pending_offers_messages.lock().unwrap();
let mut pending_invoice_request = pending_offers_messages.first_mut().unwrap();
match &mut pending_invoice_request.1 {
MessageSendInstructions::WithSpecifiedReplyPath { reply_path, .. } =>
*reply_path = invalid_reply_path,
_ => panic!(),
}
}
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
assert_ne!(invoice_request.payer_signing_pubkey(), david_id);
assert!(check_dummy_hopped_path_length(&reply_path, david, charlie_id, DUMMY_HOPS_PATH_LENGTH));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
}
#[test]
fn fails_authentication_when_handling_invoice_for_refund() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), david_id);
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert!(check_compact_path_introduction_node(&path, david, charlie_id));
}
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
connect_peers(david, alice);
match &mut alice.node.flow.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
*destination = Destination::Node(david_id),
_ => panic!(),
}
let onion_message = alice.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(david, &onion_message);
assert_eq!(invoice, expected_invoice);
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
david.node.abandon_payment(payment_id);
get_event!(david, Event::PaymentFailed);
let invalid_path = refund.paths().first().unwrap().clone();
let payment_id = PaymentId([2; 32]);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
assert_ne!(refund.payer_signing_pubkey(), david_id);
assert!(!refund.paths().is_empty());
for path in refund.paths() {
assert!(check_compact_path_introduction_node(&path, david, charlie_id));
}
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
match &mut alice.node.flow.pending_offers_messages.lock().unwrap().first_mut().unwrap().1 {
MessageSendInstructions::WithSpecifiedReplyPath { destination, .. } =>
*destination = Destination::BlindedPath(invalid_path),
_ => panic!(),
}
connect_peers(alice, charlie);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let (invoice, _) = extract_invoice(david, &onion_message);
assert_eq!(invoice, expected_invoice);
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
}
#[test]
fn fails_creating_or_paying_for_offer_without_connected_peers() {
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
disconnect_peers(alice, &[bob, charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);
match alice.node.create_offer_builder() {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
let mut args = ReconnectArgs::new(alice, bob);
args.send_channel_ready = (true, true);
reconnect_nodes(args);
let absolute_expiry = alice.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.absolute_expiry(absolute_expiry)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
match david.node.pay_for_offer(&offer, None, payment_id, Default::default()) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
assert!(nodes[0].node.list_recent_payments().is_empty());
let mut args = ReconnectArgs::new(charlie, david);
args.send_channel_ready = (true, true);
reconnect_nodes(args);
assert!(david.node.pay_for_offer(&offer, None, payment_id, Default::default()).is_ok());
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
}
#[test]
fn fails_creating_refund_or_sending_invoice_without_connected_peers() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
disconnect_peers(alice, &[bob, charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);
let absolute_expiry = david.node.duration_since_epoch() + MAX_SHORT_LIVED_RELATIVE_EXPIRY;
let payment_id = PaymentId([1; 32]);
match david.node.create_refund_builder(
10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
let mut args = ReconnectArgs::new(charlie, david);
args.send_channel_ready = (true, true);
reconnect_nodes(args);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
let mut args = ReconnectArgs::new(alice, bob);
args.send_channel_ready = (true, true);
reconnect_nodes(args);
assert!(alice.node.request_refund_payment(&refund).is_ok());
}
#[test]
fn fails_creating_invoice_request_for_unsupported_chain() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let bob = &nodes[1];
let offer = alice.node
.create_offer_builder().unwrap()
.clear_chains()
.chain(Network::Signet)
.build().unwrap();
match bob.node.pay_for_offer(&offer, None, PaymentId([1; 32]), Default::default()) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
}
}
#[test]
fn fails_sending_invoice_with_unsupported_chain_for_refund() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0];
let bob = &nodes[1];
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = bob.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.chain(Network::Signet)
.build().unwrap();
match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedChain),
}
}
#[test]
fn fails_creating_invoice_request_without_blinded_reply_path() {
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, charlie, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
match david.node.pay_for_offer(&offer, None, PaymentId([1; 32]), Default::default()) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
assert!(nodes[0].node.list_recent_payments().is_empty());
}
#[test]
fn fails_creating_invoice_request_with_duplicate_payment_id() {
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(6, &node_cfgs, &[None, None, None, None, None, None]);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, _bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
assert!(david.node.pay_for_offer( &offer, None, payment_id, Default::default()).is_ok());
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
match david.node.pay_for_offer(&offer, None, payment_id, Default::default()) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
}
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
}
#[test]
fn fails_creating_refund_with_duplicate_payment_id() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
assert!(
nodes[0].node.create_refund_builder(
10_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
).is_ok()
);
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
match nodes[0].node.create_refund_builder(
10_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default()
) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::DuplicatePaymentId),
}
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
}
#[test]
fn fails_sending_invoice_without_blinded_payment_paths_for_offer() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.clear_route_blinding();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let invoice_error = extract_invoice_error(david, &onion_message);
assert_eq!(invoice_error, InvoiceError::from(Bolt12SemanticError::MissingPaths));
match get_event!(david, Event::PaymentFailed) {
Event::PaymentFailed { payment_id: actual_payment_id, reason, .. } => {
assert_eq!(payment_id, actual_payment_id);
assert_eq!(reason, Some(PaymentFailureReason::InvoiceRequestRejected));
},
_ => panic!("No Event::PaymentFailed"),
}
}
#[test]
fn fails_sending_invoice_without_blinded_payment_paths_for_refund() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.clear_route_blinding();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
match alice.node.request_refund_payment(&refund) {
Ok(_) => panic!("Expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::MissingPaths),
}
}
#[test]
fn fails_paying_invoice_more_than_once() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let absolute_expiry = Duration::from_secs(u64::MAX);
let payment_id = PaymentId([1; 32]);
let refund = david.node
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), RouteParametersConfig::default())
.unwrap()
.build().unwrap();
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
alice.node.request_refund_payment(&refund).unwrap();
connect_peers(alice, charlie);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext { payment_metadata: None });
let (invoice1, _) = extract_invoice(david, &onion_message);
route_bolt12_payment(david, &[charlie, bob, alice], &invoice1);
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
disconnect_peers(alice, &[charlie]);
alice.node.request_refund_payment(&refund).unwrap();
connect_peers(alice, charlie);
connect_peers(david, bob);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
let (invoice2, _) = extract_invoice(david, &onion_message);
assert_eq!(invoice1.payer_metadata(), invoice2.payer_metadata());
assert!(david.onion_messenger.next_onion_message_for_peer(bob_id).is_none());
assert!(david.node.get_and_clear_pending_msg_events().is_empty());
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice1);
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
}
#[test]
fn fails_paying_invoice_with_unknown_required_features() {
let mut accept_forward_cfg = test_default_channel_config();
accept_forward_cfg.accept_forwards_to_priv_channels = true;
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
features.set_onion_messages_optional();
features.set_route_blinding_optional();
let chanmon_cfgs = create_chanmon_cfgs(6);
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
let node_chanmgrs = create_node_chanmgrs(
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
);
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
let alice_id = alice.node.get_our_node_id();
let bob_id = bob.node.get_our_node_id();
let charlie_id = charlie.node.get_our_node_id();
let david_id = david.node.get_our_node_id();
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
david.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
connect_peers(david, bob);
let onion_message = david.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(david_id, &onion_message);
connect_peers(alice, charlie);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
let nonce = extract_offer_nonce(alice, &onion_message);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
let (invoice, _) = extract_invoice(david, &onion_message);
let payment_paths = invoice.payment_paths().to_vec();
let payment_hash = invoice.payment_hash();
let expanded_key = alice.keys_manager.get_expanded_key();
let secp_ctx = Secp256k1::new();
let created_at = alice.node.duration_since_epoch();
let verified_invoice_request = invoice_request
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap();
let invoice = match verified_invoice_request {
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
request.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
.features_unchecked(Bolt12InvoiceFeatures::unknown())
.build_and_sign(&secp_ctx).unwrap()
},
InvoiceRequestVerifiedFromOffer::ExplicitKeys(_) => {
panic!("Expected invoice request with keys");
},
};
let instructions = MessageSendInstructions::WithoutReplyPath {
destination: Destination::BlindedPath(reply_path),
};
let message = OffersMessage::Invoice(invoice);
alice.node.flow.pending_offers_messages.lock().unwrap().push((message, instructions));
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
charlie.onion_messenger.handle_onion_message(alice_id, &onion_message);
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
david.onion_messenger.handle_onion_message(charlie_id, &onion_message);
match get_event!(david, Event::PaymentFailed) {
Event::PaymentFailed {
payment_id: event_payment_id,
payment_hash: Some(event_payment_hash),
reason: Some(event_reason),
} => {
assert_eq!(event_payment_id, payment_id);
assert_eq!(event_payment_hash, payment_hash);
assert_eq!(event_reason, PaymentFailureReason::UnknownRequiredFeatures);
},
_ => panic!("Expected Event::PaymentFailed with reason"),
}
}
#[test]
fn rejects_keysend_to_non_static_invoice_path() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
let offer = nodes[1].node.create_offer_builder().unwrap().build().unwrap();
let amt_msat = 5000;
let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, Some(amt_msat), payment_id, Default::default()).unwrap();
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(nodes[1].node.get_our_node_id()).unwrap();
nodes[1].onion_messenger.handle_onion_message(nodes[0].node.get_our_node_id(), &invreq_om);
let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(nodes[0].node.get_our_node_id()).unwrap();
let invoice = extract_invoice(&nodes[0], &invoice_om).0;
nodes[0].onion_messenger.handle_onion_message(nodes[1].node.get_our_node_id(), &invoice_om);
route_bolt12_payment(&nodes[0], &[&nodes[1]], &invoice);
expect_recent_payment!(nodes[0], RecentPaymentDetails::Pending, payment_id);
let payment_preimage = match get_event!(nodes[1], Event::PaymentClaimable) {
Event::PaymentClaimable { purpose, .. } => purpose.preimage().unwrap(),
_ => panic!()
};
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
expect_recent_payment!(&nodes[0], RecentPaymentDetails::Fulfilled, payment_id);
for _ in 0..=IDEMPOTENCY_TIMEOUT_TICKS {
nodes[0].node.timer_tick_occurred();
nodes[1].node.timer_tick_occurred();
}
let pay_params = PaymentParameters::from_bolt12_invoice(&invoice);
let route_params = RouteParameters::from_payment_params_and_value(pay_params, amt_msat);
let keysend_payment_id = PaymentId([2; 32]);
let payment_hash = nodes[0].node.send_spontaneous_payment(
Some(payment_preimage), RecipientOnionFields::spontaneous_empty(amt_msat), keysend_payment_id,
route_params, Retry::Attempts(0)
).unwrap();
check_added_monitors(&nodes[0], 1);
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 1);
let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events);
let route: &[&[&Node]] = &[&[&nodes[1]]];
let args = PassAlongPathArgs::new(&nodes[0], route[0], amt_msat, payment_hash, ev)
.with_payment_preimage(payment_preimage)
.expect_failure(HTLCHandlingFailureType::Receive { payment_hash })
.with_dummy_tlvs(&[DummyTlvs::default(); DEFAULT_PAYMENT_DUMMY_HOPS]);
do_pass_along_path(args);
let mut updates = get_htlc_update_msgs(&nodes[1], &nodes[0].node.get_our_node_id());
nodes[0].node.handle_update_fail_malformed_htlc(nodes[1].node.get_our_node_id(), &updates.update_fail_malformed_htlcs[0]);
do_commitment_signed_dance(&nodes[0], &nodes[1], &updates.commitment_signed, false, false);
expect_payment_failed_conditions(&nodes[0], payment_hash, false, PaymentFailedConditions::new());
}
#[test]
fn no_double_pay_with_stale_channelmanager() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let persister;
let chain_monitor;
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let alice_deserialized;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
let chan_id_0 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000).2;
let chan_id_1 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000).2;
let alice_id = nodes[0].node.get_our_node_id();
let bob_id = nodes[1].node.get_our_node_id();
let amt_msat = nodes[0].node.list_usable_channels()[0].next_outbound_htlc_limit_msat + 1; let offer = nodes[1].node
.create_offer_builder().unwrap()
.clear_paths()
.amount_msats(amt_msat)
.build().unwrap();
assert_eq!(offer.issuer_signing_pubkey(), Some(bob_id));
assert!(offer.paths().is_empty());
let payment_id = PaymentId([1; 32]);
nodes[0].node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
let invreq_om = nodes[0].onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
nodes[1].onion_messenger.handle_onion_message(alice_id, &invreq_om);
let alice_chan_manager_serialized = nodes[0].node.encode();
let invoice_om = nodes[1].onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
nodes[0].onion_messenger.handle_onion_message(bob_id, &invoice_om);
let payment_hash = extract_invoice(&nodes[0], &invoice_om).0.payment_hash();
let expected_route: &[&[&Node]] = &[&[&nodes[1]], &[&nodes[1]]];
let mut events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(events.len(), 2);
check_added_monitors(&nodes[0], 2);
let ev = remove_first_msg_event_to_node(&bob_id, &mut events);
let args = PassAlongPathArgs::new(&nodes[0], expected_route[0], amt_msat, payment_hash, ev)
.without_clearing_recipient_events()
.with_dummy_tlvs(&[DummyTlvs::default(); DEFAULT_PAYMENT_DUMMY_HOPS]);
do_pass_along_path(args);
let ev = remove_first_msg_event_to_node(&bob_id, &mut events);
let args = PassAlongPathArgs::new(&nodes[0], expected_route[0], amt_msat, payment_hash, ev)
.without_clearing_recipient_events()
.with_dummy_tlvs(&[DummyTlvs::default(); DEFAULT_PAYMENT_DUMMY_HOPS]);
do_pass_along_path(args);
expect_recent_payment!(nodes[0], RecentPaymentDetails::Pending, payment_id);
match get_event!(nodes[1], Event::PaymentClaimable) {
Event::PaymentClaimable { .. } => {},
_ => panic!("No Event::PaymentClaimable"),
}
let monitor_0 = get_monitor!(nodes[0], chan_id_0).encode();
let monitor_1 = get_monitor!(nodes[0], chan_id_1).encode();
reload_node!(nodes[0], &alice_chan_manager_serialized, &[&monitor_0, &monitor_1], persister, chain_monitor, alice_deserialized);
check_closed_event(&nodes[0], 2, ClosureReason::OutdatedChannelManager, &[bob_id, bob_id], 10_000_000);
check_added_monitors(&nodes[0], 2);
nodes[0].onion_messenger.handle_onion_message(bob_id, &invoice_om);
assert!(nodes[0].node.get_and_clear_pending_events().is_empty());
}
#[test]
fn creates_and_pays_for_phantom_offer() {
let mut chanmon_cfgs = create_chanmon_cfgs(1);
chanmon_cfgs.append(&mut create_phantom_chanmon_cfgs(2));
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 10_000_000, 1_000_000_000);
let node_a_id = nodes[0].node.get_our_node_id();
let node_b_id = nodes[1].node.get_our_node_id();
let node_c_id = nodes[2].node.get_our_node_id();
let offer = nodes[1].node
.create_phantom_offer_builder(vec![(node_c_id, nodes[2].node.list_channels())], 2)
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
assert!(offer.issuer_signing_pubkey().is_some());
assert_ne!(offer.issuer_signing_pubkey(), Some(node_b_id));
assert_ne!(offer.issuer_signing_pubkey(), Some(node_c_id));
assert_eq!(offer.paths().len(), 2);
let mut b_path_count = 0;
let mut c_path_count = 0;
for path in offer.paths() {
if check_compact_path_introduction_node(&path, &nodes[0], node_b_id) {
b_path_count += 1;
}
if check_compact_path_introduction_node(&path, &nodes[0], node_c_id) {
c_path_count += 1;
}
}
assert_eq!(b_path_count, 1);
assert_eq!(c_path_count, 1);
for (payment_id, recipient) in [([1; 32], &nodes[1]), ([2; 32], &nodes[2])] {
let payment_id = PaymentId(payment_id);
nodes[0].node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(nodes[0], RecentPaymentDetails::AwaitingInvoice, payment_id);
let recipient_id = recipient.node.get_our_node_id();
let non_recipient_id = if node_b_id == recipient_id {
node_c_id
} else {
node_b_id
};
let onion_message =
nodes[0].onion_messenger.next_onion_message_for_peer(recipient_id).unwrap();
let _discard =
nodes[0].onion_messenger.next_onion_message_for_peer(non_recipient_id).unwrap();
recipient.onion_messenger.handle_onion_message(node_a_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(&recipient, &onion_message);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: offer.id(),
invoice_request: InvoiceRequestFields {
payer_signing_pubkey: invoice_request.payer_signing_pubkey(),
quantity: None,
payer_note_truncated: None,
human_readable_name: None,
},
payment_metadata: None,
});
let onion_message =
recipient.onion_messenger.next_onion_message_for_peer(node_a_id).unwrap();
nodes[0].onion_messenger.handle_onion_message(recipient_id, &onion_message);
let (invoice, _) = extract_invoice(&nodes[0], &onion_message);
assert_eq!(invoice.amount_msats(), 10_000_000);
route_bolt12_payment(&nodes[0], &[recipient], &invoice);
expect_recent_payment!(&nodes[0], RecentPaymentDetails::Pending, payment_id);
claim_bolt12_payment(&nodes[0], &[recipient], payment_context, &invoice);
expect_recent_payment!(&nodes[0], RecentPaymentDetails::Fulfilled, payment_id);
assert!(nodes[0].onion_messenger.next_onion_message_for_peer(node_b_id).is_none());
assert!(nodes[0].onion_messenger.next_onion_message_for_peer(node_c_id).is_none());
}
}
#[test]
fn creates_and_verifies_payer_proof_after_offer_payment() {
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
let alice = &nodes[0]; let alice_id = alice.node.get_our_node_id();
let bob = &nodes[1]; let bob_id = bob.node.get_our_node_id();
let offer = alice.node
.create_offer_builder().unwrap()
.amount_msats(10_000_000)
.build().unwrap();
let payment_id = PaymentId([1; 32]);
bob.node.pay_for_offer(&offer, None, payment_id, Default::default()).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
let (invoice_request, _) = extract_invoice_request(alice, &onion_message);
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
let (invoice, _) = extract_invoice(bob, &onion_message);
assert_eq!(invoice.amount_msats(), 10_000_000);
let context_payment_id = extract_payer_context(bob, &onion_message);
assert_eq!(context_payment_id, payment_id);
route_bolt12_payment(bob, &[alice], &invoice);
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
let payment_preimage = match get_event!(alice, Event::PaymentClaimable) {
Event::PaymentClaimable { purpose, .. } => {
match &purpose {
PaymentPurpose::Bolt12OfferPayment { payment_context, .. } => {
assert_eq!(payment_context.offer_id, offer.id());
assert_eq!(
payment_context.invoice_request.payer_signing_pubkey,
invoice_request.payer_signing_pubkey(),
);
},
_ => panic!("Expected Bolt12OfferPayment purpose"),
}
purpose.preimage().unwrap()
},
_ => panic!("Expected Event::PaymentClaimable"),
};
let paid_invoice = claim_payment(bob, &[alice], payment_preimage).unwrap();
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
assert!(paid_invoice.bolt12_invoice().is_some());
let payment_sent = Event::PaymentSent {
payment_id: Some(payment_id),
payment_preimage,
payment_hash: invoice.payment_hash(),
amount_msat: Some(10_000_000),
fee_paid_msat: None,
bolt12_invoice: Some(paid_invoice.clone()),
};
let encoded = payment_sent.encode();
let decoded = Event::read(&mut &encoded[..]).unwrap().unwrap();
assert_eq!(decoded, payment_sent);
match decoded {
Event::PaymentSent { bolt12_invoice: Some(decoded_invoice), .. } => {
assert!(decoded_invoice.bolt12_invoice().is_some());
},
_ => panic!("expected a PaymentSent event carrying a paid invoice"),
}
let expanded_key = bob.keys_manager.get_expanded_key();
let secp_ctx = Secp256k1::new();
let payer_proof = paid_invoice.prove_payer_derived(
payment_preimage, &expanded_key, payment_id, &secp_ctx,
).unwrap()
.include_offer_description()
.include_invoice_amount()
.include_invoice_created_at()
.build_and_sign()
.unwrap();
assert_eq!(payer_proof.payment_preimage(), payment_preimage);
assert_eq!(payer_proof.payment_hash(), invoice.payment_hash());
let encoded = payer_proof.to_string();
let verified: PayerProof = encoded.parse().unwrap();
assert_eq!(verified.bytes(), payer_proof.bytes());
assert_eq!(verified.to_string(), encoded);
assert_eq!(verified.payment_preimage(), payment_preimage);
assert_eq!(verified.payment_hash(), invoice.payment_hash());
assert_eq!(verified.payer_signing_pubkey(), invoice_request.payer_signing_pubkey());
assert_eq!(verified.issuer_signing_pubkey(), invoice.signing_pubkey());
assert_eq!(verified.invoice_amount_msats(), Some(invoice.amount_msats()));
assert_eq!(verified.invoice_created_at(), Some(invoice.created_at()));
assert_eq!(
verified.offer_description().map(|desc| desc.to_string()),
offer.description().map(|desc| desc.to_string()),
);
}