Skip to content

Commit 16390e6

Browse files
LSPS2: Make opening_fee_params_menu order compliant with spec
1 parent b8673f3 commit 16390e6

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

lightning-liquidity/src/lsps2/service.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use alloc::string::{String, ToString};
1313
use alloc::vec::Vec;
1414

15+
use core::cmp::Ordering as CmpOrdering;
1516
use core::ops::Deref;
1617
use core::sync::atomic::{AtomicUsize, Ordering};
1718

@@ -645,13 +646,21 @@ where
645646

646647
match self.remove_pending_request(&mut peer_state_lock, &request_id) {
647648
Some(LSPS2Request::GetInfo(_)) => {
648-
let response = LSPS2Response::GetInfo(LSPS2GetInfoResponse {
649-
opening_fee_params_menu: opening_fee_params_menu
649+
let mut opening_fee_params_menu: Vec<LSPS2OpeningFeeParams> =
650+
opening_fee_params_menu
650651
.into_iter()
651652
.map(|param| {
652653
param.into_opening_fee_params(&self.config.promise_secret)
653654
})
654-
.collect(),
655+
.collect();
656+
opening_fee_params_menu.sort_by(|a, b| {
657+
match a.min_fee_msat.cmp(&b.min_fee_msat) {
658+
CmpOrdering::Equal => a.proportional.cmp(&b.proportional),
659+
other => other,
660+
}
661+
});
662+
let response = LSPS2Response::GetInfo(LSPS2GetInfoResponse {
663+
opening_fee_params_menu,
655664
});
656665
(Ok(()), Some(response))
657666
},

lightning-liquidity/tests/lsps2_integration_tests.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,3 +746,75 @@ fn invalid_token_flow() {
746746
panic!("Expected LSPS2ClientEvent::GetInfoFailed event");
747747
}
748748
}
749+
750+
#[test]
751+
fn opening_fee_params_menu_is_sorted_by_spec() {
752+
let (service_node_id, client_node_id, service_node, client_node, _secret) =
753+
setup_test_lsps2("opening_fee_params_menu_is_sorted_by_spec");
754+
755+
let client_handler = client_node.liquidity_manager.lsps2_client_handler().unwrap();
756+
let service_handler = service_node.liquidity_manager.lsps2_service_handler().unwrap();
757+
758+
let _ = client_handler.request_opening_params(service_node_id, None);
759+
let get_info_request = get_lsps_message!(client_node, service_node_id);
760+
service_node.liquidity_manager.handle_custom_message(get_info_request, client_node_id).unwrap();
761+
762+
let get_info_event = service_node.liquidity_manager.next_event().unwrap();
763+
let request_id = match get_info_event {
764+
LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::GetInfo { request_id, .. }) => request_id,
765+
_ => panic!("Unexpected event"),
766+
};
767+
768+
let raw_params_generator = |min_fee_msat: u64, proportional: u32| LSPS2RawOpeningFeeParams {
769+
min_fee_msat,
770+
proportional,
771+
valid_until: LSPSDateTime::from_str("2035-05-20T08:30:45Z").unwrap(),
772+
min_lifetime: 144,
773+
max_client_to_self_delay: 128,
774+
min_payment_size_msat: 1,
775+
max_payment_size_msat: 100_000_000,
776+
};
777+
778+
let raw_params = vec![
779+
raw_params_generator(200, 20), // Will be sorted to position 2
780+
raw_params_generator(100, 10), // Will be sorted to position 0 (lowest min_fee, lowest proportional)
781+
raw_params_generator(300, 30), // Will be sorted to position 4 (highest min_fee, highest proportional)
782+
raw_params_generator(100, 20), // Will be sorted to position 1 (same min_fee as 0, higher proportional)
783+
raw_params_generator(200, 30), // Will be sorted to position 3 (higher min_fee than 2, higher proportional)
784+
];
785+
786+
service_handler
787+
.opening_fee_params_generated(&client_node_id, request_id.clone(), raw_params)
788+
.unwrap();
789+
790+
let get_info_response = get_lsps_message!(service_node, client_node_id);
791+
client_node
792+
.liquidity_manager
793+
.handle_custom_message(get_info_response, service_node_id)
794+
.unwrap();
795+
796+
let event = client_node.liquidity_manager.next_event().unwrap();
797+
if let LiquidityEvent::LSPS2Client(LSPS2ClientEvent::OpeningParametersReady {
798+
opening_fee_params_menu,
799+
..
800+
}) = event
801+
{
802+
// The LSP, when ordering the opening_fee_params_menu array, MUST order by the following rules:
803+
// The 0th item MAY have any parameters.
804+
// Each succeeding item MUST, compared to the previous item, obey any one of the following:
805+
// Have a larger min_fee_msat, and equal proportional.
806+
// Have a larger proportional, and equal min_fee_msat.
807+
// Have a larger min_fee_msat, AND larger proportional.
808+
for (cur, next) in
809+
opening_fee_params_menu.iter().zip(opening_fee_params_menu.iter().skip(1))
810+
{
811+
let valid = (next.min_fee_msat > cur.min_fee_msat
812+
&& next.proportional == cur.proportional)
813+
|| (next.proportional > cur.proportional && next.min_fee_msat == cur.min_fee_msat)
814+
|| (next.min_fee_msat > cur.min_fee_msat && next.proportional > cur.proportional);
815+
assert!(valid, "Params not sorted as per spec");
816+
}
817+
} else {
818+
panic!("Unexpected event");
819+
}
820+
}

0 commit comments

Comments
 (0)