Skip to content

Commit a0b7847

Browse files
committed
Add integration coverage for LSPS2 BOLT12 router path
Exercise the LSPS2 buy flow and assert that a registered `OfferId` produces a blinded payment path whose first forwarding hop uses the negotiated intercept `SCID`. This validates the custom-router wiring used for LSPS2 + `BOLT12`. Co-Authored-By: HAL 9000
1 parent c8bb1d9 commit a0b7847

1 file changed

Lines changed: 131 additions & 1 deletion

File tree

lightning-liquidity/tests/lsps2_integration_tests.rs

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,29 @@ use lightning::ln::msgs::BaseMessageHandler;
1515
use lightning::ln::msgs::ChannelMessageHandler;
1616
use lightning::ln::msgs::MessageSendEvent;
1717
use lightning::ln::types::ChannelId;
18+
use lightning::offers::invoice_request::InvoiceRequestFields;
19+
use lightning::offers::offer::OfferId;
20+
use lightning::routing::router::{InFlightHtlcs, Route, RouteParameters, Router};
21+
use lightning::sign::ReceiveAuthKey;
1822

1923
use lightning_liquidity::events::LiquidityEvent;
2024
use lightning_liquidity::lsps0::ser::LSPSDateTime;
2125
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
2226
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;
2327
use lightning_liquidity::lsps2::event::LSPS2ServiceEvent;
2428
use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
29+
use lightning_liquidity::lsps2::router::{LSPS2BOLT12Router, LSPS2Bolt12InvoiceParameters};
2530
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig;
2631
use lightning_liquidity::lsps2::utils::is_valid_opening_fee_params;
2732
use lightning_liquidity::utils::time::{DefaultTimeProvider, TimeProvider};
2833
use lightning_liquidity::{LiquidityClientConfig, LiquidityManagerSync, LiquidityServiceConfig};
2934

30-
use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
35+
use lightning::blinded_path::payment::{
36+
Bolt12OfferContext, PaymentConstraints, PaymentContext, ReceiveTlvs,
37+
};
38+
use lightning::blinded_path::NodeIdLookUp;
39+
use lightning::chain::{BestBlock, Filter};
40+
use lightning::ln::channelmanager::{ChainParameters, InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
3141
use lightning::ln::functional_test_utils::{
3242
create_chanmon_cfgs, create_node_cfgs, create_node_chanmgrs,
3343
};
@@ -56,6 +66,46 @@ use std::time::Duration;
5666
const MAX_PENDING_REQUESTS_PER_PEER: usize = 10;
5767
const MAX_TOTAL_PENDING_REQUESTS: usize = 1000;
5868

69+
struct RecordingLookup {
70+
next_node_id: PublicKey,
71+
short_channel_id: std::sync::Mutex<Option<u64>>,
72+
}
73+
74+
impl NodeIdLookUp for RecordingLookup {
75+
fn next_node_id(&self, short_channel_id: u64) -> Option<PublicKey> {
76+
*self.short_channel_id.lock().unwrap() = Some(short_channel_id);
77+
Some(self.next_node_id)
78+
}
79+
}
80+
81+
struct FailingRouter;
82+
83+
impl FailingRouter {
84+
fn new() -> Self {
85+
Self
86+
}
87+
}
88+
89+
impl Router for FailingRouter {
90+
fn find_route(
91+
&self, _payer: &PublicKey, _route_params: &RouteParameters,
92+
_first_hops: Option<&[&lightning::ln::channel_state::ChannelDetails]>,
93+
_inflight_htlcs: InFlightHtlcs,
94+
) -> Result<Route, &'static str> {
95+
Err("failing test router")
96+
}
97+
98+
fn create_blinded_payment_paths<
99+
T: bitcoin::secp256k1::Signing + bitcoin::secp256k1::Verification,
100+
>(
101+
&self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey,
102+
_first_hops: Vec<lightning::ln::channel_state::ChannelDetails>, _tlvs: ReceiveTlvs,
103+
_amount_msats: Option<u64>, _secp_ctx: &Secp256k1<T>,
104+
) -> Result<Vec<lightning::blinded_path::payment::BlindedPaymentPath>, ()> {
105+
Err(())
106+
}
107+
}
108+
59109
fn build_lsps2_configs() -> ([u8; 32], LiquidityServiceConfig, LiquidityClientConfig) {
60110
let promise_secret = [42; 32];
61111
let lsps2_service_config = LSPS2ServiceConfig { promise_secret };
@@ -1477,6 +1527,86 @@ fn execute_lsps2_dance(
14771527
}
14781528
}
14791529

1530+
#[test]
1531+
fn bolt12_custom_router_uses_lsps2_intercept_scid() {
1532+
let chanmon_cfgs = create_chanmon_cfgs(3);
1533+
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
1534+
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
1535+
let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
1536+
let (lsps_nodes, promise_secret) = setup_test_lsps2_nodes_with_payer(nodes);
1537+
1538+
let service_node_id = lsps_nodes.service_node.inner.node.get_our_node_id();
1539+
let client_node_id = lsps_nodes.client_node.inner.node.get_our_node_id();
1540+
1541+
let intercept_scid = lsps_nodes.service_node.node.get_intercept_scid();
1542+
let cltv_expiry_delta = 72;
1543+
1544+
execute_lsps2_dance(
1545+
&lsps_nodes,
1546+
intercept_scid,
1547+
42,
1548+
cltv_expiry_delta,
1549+
promise_secret,
1550+
Some(250_000),
1551+
1_000,
1552+
);
1553+
1554+
let inner_router = FailingRouter::new();
1555+
let router = LSPS2BOLT12Router::new(inner_router, lsps_nodes.client_node.keys_manager);
1556+
let offer_id = OfferId([42; 32]);
1557+
1558+
router.register_offer(
1559+
offer_id,
1560+
LSPS2Bolt12InvoiceParameters {
1561+
counterparty_node_id: service_node_id,
1562+
intercept_scid,
1563+
cltv_expiry_delta,
1564+
},
1565+
);
1566+
1567+
let tlvs = ReceiveTlvs {
1568+
payment_secret: lightning_types::payment::PaymentSecret([7; 32]),
1569+
payment_constraints: PaymentConstraints { max_cltv_expiry: 50, htlc_minimum_msat: 1 },
1570+
payment_context: PaymentContext::Bolt12Offer(Bolt12OfferContext {
1571+
offer_id,
1572+
invoice_request: InvoiceRequestFields {
1573+
payer_signing_pubkey: lsps_nodes.payer_node.node.get_our_node_id(),
1574+
quantity: None,
1575+
payer_note_truncated: None,
1576+
human_readable_name: None,
1577+
},
1578+
}),
1579+
};
1580+
1581+
let secp_ctx = Secp256k1::new();
1582+
let mut paths = router
1583+
.create_blinded_payment_paths(
1584+
client_node_id,
1585+
ReceiveAuthKey([3; 32]),
1586+
Vec::new(),
1587+
tlvs,
1588+
Some(100_000),
1589+
&secp_ctx,
1590+
)
1591+
.unwrap();
1592+
1593+
assert_eq!(paths.len(), 1);
1594+
let mut path = paths.pop().unwrap();
1595+
assert_eq!(
1596+
path.introduction_node(),
1597+
&lightning::blinded_path::IntroductionNode::NodeId(service_node_id)
1598+
);
1599+
assert_eq!(path.payinfo.fee_base_msat, 0);
1600+
assert_eq!(path.payinfo.fee_proportional_millionths, 0);
1601+
1602+
let lookup = RecordingLookup {
1603+
next_node_id: client_node_id,
1604+
short_channel_id: std::sync::Mutex::new(None),
1605+
};
1606+
path.advance_path_by_one(lsps_nodes.service_node.keys_manager, &lookup, &secp_ctx).unwrap();
1607+
assert_eq!(*lookup.short_channel_id.lock().unwrap(), Some(intercept_scid));
1608+
}
1609+
14801610
fn create_channel_with_manual_broadcast(
14811611
service_node_id: &PublicKey, client_node_id: &PublicKey, service_node: &LiquidityNode,
14821612
client_node: &LiquidityNode, user_channel_id: u128, expected_outbound_amount_msat: &u64,

0 commit comments

Comments
 (0)