Skip to content

Commit 2d5dd45

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 0e7bfa7 commit 2d5dd45

1 file changed

Lines changed: 129 additions & 0 deletions

File tree

lightning-liquidity/tests/lsps2_integration_tests.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,27 @@ 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

35+
use lightning::blinded_path::payment::{
36+
Bolt12OfferContext, PaymentConstraints, PaymentContext, ReceiveTlvs,
37+
};
38+
use lightning::blinded_path::NodeIdLookUp;
3039
use lightning::chain::{BestBlock, Filter};
3140
use lightning::ln::channelmanager::{ChainParameters, InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
3241
use lightning::ln::functional_test_utils::{
@@ -57,6 +66,46 @@ use std::time::Duration;
5766
const MAX_PENDING_REQUESTS_PER_PEER: usize = 10;
5867
const MAX_TOTAL_PENDING_REQUESTS: usize = 1000;
5968

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+
60109
fn build_lsps2_configs() -> ([u8; 32], LiquidityServiceConfig, LiquidityClientConfig) {
61110
let promise_secret = [42; 32];
62111
let lsps2_service_config = LSPS2ServiceConfig { promise_secret };
@@ -1487,6 +1536,86 @@ fn execute_lsps2_dance(
14871536
}
14881537
}
14891538

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

0 commit comments

Comments
 (0)