Skip to content

Commit fd6a0e6

Browse files
committed
Introduce test for padding
1. Add tests to verify that both blinded message paths and blinded payment paths are properly padded. 2. Introduce a test utility function to ensure consistency and keep the code DRY.
1 parent 2160528 commit fd6a0e6

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

lightning/src/ln/offers_tests.rs

+83
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use crate::offers::invoice::Bolt12Invoice;
5454
use crate::offers::invoice_error::InvoiceError;
5555
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
5656
use crate::offers::parse::Bolt12SemanticError;
57+
use crate::offers::test_utils::is_properly_padded;
5758
use crate::onion_message::messenger::PeeledOnion;
5859
use crate::onion_message::offers::OffersMessage;
5960
use crate::onion_message::packet::ParsedOnionMessageContents;
@@ -1560,3 +1561,85 @@ fn fails_paying_invoice_more_than_once() {
15601561
let invoice_error = extract_invoice_error(alice, &onion_message);
15611562
assert_eq!(invoice_error, InvoiceError::from_string("DuplicateInvoice".to_string()));
15621563
}
1564+
1565+
/// This test verifies that both the blinded message paths and blinded payment
1566+
/// paths are properly padded and function as expected.
1567+
#[test]
1568+
fn test_blinded_path_padding() {
1569+
let mut accept_forward_cfg = test_default_channel_config();
1570+
accept_forward_cfg.accept_forwards_to_priv_channels = true;
1571+
1572+
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
1573+
features.set_onion_messages_optional();
1574+
features.set_route_blinding_optional();
1575+
1576+
let chanmon_cfgs = create_chanmon_cfgs(6);
1577+
let node_cfgs = create_node_cfgs(6, &chanmon_cfgs);
1578+
1579+
*node_cfgs[1].override_init_features.borrow_mut() = Some(features);
1580+
1581+
let node_chanmgrs = create_node_chanmgrs(
1582+
6, &node_cfgs, &[None, Some(accept_forward_cfg), None, None, None, None]
1583+
);
1584+
let nodes = create_network(6, &node_cfgs, &node_chanmgrs);
1585+
1586+
create_unannounced_chan_between_nodes_with_value(&nodes, 0, 1, 10_000_000, 1_000_000_000);
1587+
create_unannounced_chan_between_nodes_with_value(&nodes, 2, 3, 10_000_000, 1_000_000_000);
1588+
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 10_000_000, 1_000_000_000);
1589+
create_announced_chan_between_nodes_with_value(&nodes, 1, 4, 10_000_000, 1_000_000_000);
1590+
create_announced_chan_between_nodes_with_value(&nodes, 1, 5, 10_000_000, 1_000_000_000);
1591+
create_announced_chan_between_nodes_with_value(&nodes, 2, 4, 10_000_000, 1_000_000_000);
1592+
create_announced_chan_between_nodes_with_value(&nodes, 2, 5, 10_000_000, 1_000_000_000);
1593+
1594+
let (alice, bob, charlie, david) = (&nodes[0], &nodes[1], &nodes[2], &nodes[3]);
1595+
let alice_id = alice.node.get_our_node_id();
1596+
let bob_id = bob.node.get_our_node_id();
1597+
let charlie_id = charlie.node.get_our_node_id();
1598+
let david_id = david.node.get_our_node_id();
1599+
1600+
disconnect_peers(alice, &[charlie, david, &nodes[4], &nodes[5]]);
1601+
disconnect_peers(david, &[bob, &nodes[4], &nodes[5]]);
1602+
1603+
let absolute_expiry = Duration::from_secs(u64::MAX);
1604+
let payment_id = PaymentId([1; 32]);
1605+
let refund = david.node
1606+
.create_refund_builder(10_000_000, absolute_expiry, payment_id, Retry::Attempts(0), None)
1607+
.unwrap()
1608+
.build().unwrap();
1609+
assert!(!refund.paths().is_empty());
1610+
for path in refund.paths() {
1611+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(charlie_id));
1612+
// Verify that the blinded message paths are properly padded.
1613+
is_properly_padded(path);
1614+
}
1615+
expect_recent_payment!(david, RecentPaymentDetails::AwaitingInvoice, payment_id);
1616+
1617+
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
1618+
let expected_invoice = alice.node.request_refund_payment(&refund).unwrap();
1619+
1620+
connect_peers(alice, charlie);
1621+
1622+
let onion_message = alice.onion_messenger.next_onion_message_for_peer(charlie_id).unwrap();
1623+
charlie.onion_messenger.handle_onion_message(&alice_id, &onion_message);
1624+
1625+
let onion_message = charlie.onion_messenger.next_onion_message_for_peer(david_id).unwrap();
1626+
david.onion_messenger.handle_onion_message(&charlie_id, &onion_message);
1627+
1628+
let invoice = extract_invoice(david, &onion_message);
1629+
assert_eq!(invoice, expected_invoice);
1630+
1631+
assert_eq!(invoice.amount_msats(), 10_000_000);
1632+
assert_ne!(invoice.signing_pubkey(), alice_id);
1633+
assert!(!invoice.payment_paths().is_empty());
1634+
for (_, path) in invoice.payment_paths() {
1635+
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
1636+
// Verify that the blinded payment paths are properly padded.
1637+
is_properly_padded(path);
1638+
}
1639+
1640+
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
1641+
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
1642+
1643+
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
1644+
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
1645+
}

lightning/src/offers/test_utils.rs

+7
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,10 @@ impl EntropySource for FixedEntropy {
125125
[42; 32]
126126
}
127127
}
128+
129+
/// Checks if all the packets in the blinded path are properly padded, ensuring they are of equal size.
130+
pub fn is_properly_padded(path: &BlindedPath) -> bool {
131+
let first_hop = path.blinded_hops.first().expect("BlindedPath must have at least one hop");
132+
let first_payload_size = first_hop.encrypted_payload.len();
133+
path.blinded_hops.iter().all(|hop| hop.encrypted_payload.len() == first_payload_size)
134+
}

0 commit comments

Comments
 (0)