Skip to content

Commit cb66a95

Browse files
fixup: make OutboundJITChannelState private, and do bool helper for checking if lsps2 has any pendingChannelOpen or above
1 parent 1eb5051 commit cb66a95

File tree

4 files changed

+104
-157
lines changed

4 files changed

+104
-157
lines changed

lightning-liquidity/src/lsps2/service.rs

Lines changed: 14 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,9 @@ struct ForwardPaymentAction(ChannelId, FeePayment);
107107
#[derive(Debug, PartialEq)]
108108
struct ForwardHTLCsAction(ChannelId, Vec<InterceptedHTLC>);
109109

110-
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
111-
pub(crate) enum OutboundJITStage {
112-
PendingInitialPayment,
113-
PendingChannelOpen,
114-
PendingPaymentForward,
115-
PendingPayment,
116-
PaymentForwarded,
117-
}
118-
119110
/// The different states a requested JIT channel can be in.
120-
#[derive(Debug, PartialEq, Eq, Clone)]
121-
pub(crate) enum OutboundJITChannelState {
111+
#[derive(Debug)]
112+
enum OutboundJITChannelState {
122113
/// The JIT channel SCID was created after a buy request, and we are awaiting an initial payment
123114
/// of sufficient size to open the channel.
124115
PendingInitialPayment { payment_queue: PaymentQueue },
@@ -143,36 +134,6 @@ pub(crate) enum OutboundJITChannelState {
143134
PaymentForwarded { channel_id: ChannelId },
144135
}
145136

146-
impl OutboundJITChannelState {
147-
pub(crate) fn stage(&self) -> OutboundJITStage {
148-
match self {
149-
OutboundJITChannelState::PendingInitialPayment { .. } => {
150-
OutboundJITStage::PendingInitialPayment
151-
},
152-
OutboundJITChannelState::PendingChannelOpen { .. } => {
153-
OutboundJITStage::PendingChannelOpen
154-
},
155-
OutboundJITChannelState::PendingPaymentForward { .. } => {
156-
OutboundJITStage::PendingPaymentForward
157-
},
158-
OutboundJITChannelState::PendingPayment { .. } => OutboundJITStage::PendingPayment,
159-
OutboundJITChannelState::PaymentForwarded { .. } => OutboundJITStage::PaymentForwarded,
160-
}
161-
}
162-
}
163-
164-
impl PartialOrd for OutboundJITChannelState {
165-
fn partial_cmp(&self, other: &Self) -> Option<CmpOrdering> {
166-
Some(self.cmp(other))
167-
}
168-
}
169-
170-
impl Ord for OutboundJITChannelState {
171-
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
172-
self.stage().cmp(&other.stage())
173-
}
174-
}
175-
176137
impl OutboundJITChannelState {
177138
fn new() -> Self {
178139
OutboundJITChannelState::PendingInitialPayment { payment_queue: PaymentQueue::new() }
@@ -605,13 +566,20 @@ where
605566
&self.config
606567
}
607568

608-
pub(crate) fn highest_state_for_peer(
609-
&self, counterparty_node_id: &PublicKey,
610-
) -> Option<OutboundJITChannelState> {
569+
/// Returns whether the peer has any opening or open JIT channels.
570+
pub(crate) fn has_opening_or_open_jit_channel(&self, counterparty_node_id: &PublicKey) -> bool {
611571
let outer_state_lock = self.per_peer_state.read().unwrap();
612-
outer_state_lock.get(counterparty_node_id).and_then(|inner| {
572+
outer_state_lock.get(counterparty_node_id).map_or(false, |inner| {
613573
let peer_state = inner.lock().unwrap();
614-
peer_state.outbound_channels_by_intercept_scid.values().map(|c| c.state.clone()).max()
574+
peer_state.outbound_channels_by_intercept_scid.values().any(|chan| {
575+
matches!(
576+
chan.state,
577+
OutboundJITChannelState::PendingChannelOpen { .. }
578+
| OutboundJITChannelState::PendingPaymentForward { .. }
579+
| OutboundJITChannelState::PendingPayment { .. }
580+
| OutboundJITChannelState::PaymentForwarded { .. }
581+
)
582+
})
615583
})
616584
}
617585

@@ -1948,55 +1916,4 @@ mod tests {
19481916
);
19491917
}
19501918
}
1951-
1952-
#[test]
1953-
fn highest_state_for_peer_orders() {
1954-
let opening_fee_params = LSPS2OpeningFeeParams {
1955-
min_fee_msat: 0,
1956-
proportional: 0,
1957-
valid_until: LSPSDateTime::from_str("1970-01-01T00:00:00Z").unwrap(),
1958-
min_lifetime: 0,
1959-
max_client_to_self_delay: 0,
1960-
min_payment_size_msat: 0,
1961-
max_payment_size_msat: 0,
1962-
promise: String::new(),
1963-
};
1964-
1965-
let mut map = new_hash_map();
1966-
map.insert(
1967-
0,
1968-
OutboundJITChannel {
1969-
state: OutboundJITChannelState::PendingInitialPayment {
1970-
payment_queue: PaymentQueue::new(),
1971-
},
1972-
user_channel_id: 0,
1973-
opening_fee_params: opening_fee_params.clone(),
1974-
payment_size_msat: None,
1975-
},
1976-
);
1977-
map.insert(
1978-
1,
1979-
OutboundJITChannel {
1980-
state: OutboundJITChannelState::PendingChannelOpen {
1981-
payment_queue: PaymentQueue::new(),
1982-
opening_fee_msat: 0,
1983-
},
1984-
user_channel_id: 1,
1985-
opening_fee_params: opening_fee_params.clone(),
1986-
payment_size_msat: None,
1987-
},
1988-
);
1989-
map.insert(
1990-
2,
1991-
OutboundJITChannel {
1992-
state: OutboundJITChannelState::PaymentForwarded { channel_id: ChannelId([0; 32]) },
1993-
user_channel_id: 2,
1994-
opening_fee_params,
1995-
payment_size_msat: None,
1996-
},
1997-
);
1998-
1999-
let max_state = map.values().map(|c| c.state.clone()).max().unwrap();
2000-
assert!(matches!(max_state, OutboundJITChannelState::PaymentForwarded { .. }));
2001-
}
20021919
}

lightning-liquidity/src/lsps5/service.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use crate::prelude::*;
2121
use crate::sync::{Arc, Mutex, RwLock, RwLockWriteGuard};
2222
use crate::utils::time::TimeProvider;
2323

24-
use crate::lsps2::service::{OutboundJITChannelState, OutboundJITStage};
2524
use bitcoin::secp256k1::PublicKey;
2625

2726
use lightning::ln::channelmanager::AChannelManager;
@@ -153,15 +152,14 @@ where
153152
/// Returns whether a request from the given client should be accepted.
154153
///
155154
/// Prior activity includes an existing open channel, an active LSPS1 flow,
156-
/// or an LSPS2 flow that has progressed to at least
157-
/// [`OutboundJITChannelState::PendingChannelOpen`].
155+
/// or an LSPS2 flow that has an opening or open JIT channel.
158156
pub(crate) fn can_accept_request(
159-
&self, client_id: &PublicKey, lsps2_max_state: Option<OutboundJITChannelState>,
157+
&self, client_id: &PublicKey, lsps2_has_opening_or_open_jit_channel: bool,
160158
lsps1_has_activity: bool,
161159
) -> bool {
162160
self.client_has_open_channel(client_id)
161+
|| lsps2_has_opening_or_open_jit_channel
163162
|| lsps1_has_activity
164-
|| lsps2_max_state.map_or(false, |s| s.stage() >= OutboundJITStage::PendingChannelOpen)
165163
}
166164

167165
fn check_prune_stale_webhooks<'a>(
@@ -502,7 +500,7 @@ where
502500
.map_err(|_| LSPS5ProtocolError::UnknownError)
503501
}
504502

505-
pub(crate) fn client_has_open_channel(&self, client_id: &PublicKey) -> bool {
503+
fn client_has_open_channel(&self, client_id: &PublicKey) -> bool {
506504
self.channel_manager
507505
.get_cm()
508506
.list_channels()

lightning-liquidity/src/manager.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,10 +568,10 @@ where
568568
LSPSMessage::LSPS5(msg @ LSPS5Message::Request(..)) => {
569569
match &self.lsps5_service_handler {
570570
Some(lsps5_service_handler) => {
571-
let lsps2_max_state = self
571+
let lsps2_has_opening_or_open_jit_channel = self
572572
.lsps2_service_handler
573573
.as_ref()
574-
.and_then(|h| h.highest_state_for_peer(sender_node_id));
574+
.map_or(false, |h| h.has_opening_or_open_jit_channel(sender_node_id));
575575
#[cfg(lsps1_service)]
576576
let lsps1_has_active_requests = self
577577
.lsps1_service_handler
@@ -582,7 +582,7 @@ where
582582

583583
if !lsps5_service_handler.can_accept_request(
584584
sender_node_id,
585-
lsps2_max_state,
585+
lsps2_has_opening_or_open_jit_channel,
586586
lsps1_has_active_requests,
587587
) {
588588
return Err(LightningError {

lightning-liquidity/tests/lsps5_integration_tests.rs

Lines changed: 83 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,49 @@ fn test_notifications_and_peer_connected_resets_cooldown() {
12301230
}
12311231
}
12321232

1233+
macro_rules! assert_lsps5_reject {
1234+
($client_handler:expr, $service_node:expr, $client_node:expr, $service_node_id:expr, $client_node_id:expr) => {{
1235+
let _ = $client_handler
1236+
.set_webhook(
1237+
$service_node_id,
1238+
"App".to_string(),
1239+
"https://example.org/webhook".to_string(),
1240+
)
1241+
.expect("Request should send");
1242+
let request = get_lsps_message!($client_node, $service_node_id);
1243+
1244+
let result =
1245+
$service_node.liquidity_manager.handle_custom_message(request, $client_node_id);
1246+
assert!(result.is_err(), "Service should reject request without prior interaction");
1247+
1248+
assert!($service_node.liquidity_manager.get_and_clear_pending_msg().is_empty());
1249+
}};
1250+
}
1251+
1252+
macro_rules! assert_lsps5_accept {
1253+
($client_handler:expr, $service_node:expr, $client_node:expr, $service_node_id:expr, $client_node_id:expr) => {{
1254+
let _ = $client_handler
1255+
.set_webhook(
1256+
$service_node_id,
1257+
"App".to_string(),
1258+
"https://example.org/webhook".to_string(),
1259+
)
1260+
.expect("Request should send");
1261+
let request = get_lsps_message!($client_node, $service_node_id);
1262+
1263+
let result =
1264+
$service_node.liquidity_manager.handle_custom_message(request, $client_node_id);
1265+
assert!(result.is_ok(), "Service should accept request after prior interaction");
1266+
let _ = $service_node.liquidity_manager.next_event().unwrap();
1267+
let response = get_lsps_message!($service_node, $client_node_id);
1268+
$client_node
1269+
.liquidity_manager
1270+
.handle_custom_message(response, $service_node_id)
1271+
.expect("Client should handle response");
1272+
let _ = $client_node.liquidity_manager.next_event().unwrap();
1273+
}};
1274+
}
1275+
12331276
#[test]
12341277
fn webhook_update_affects_future_notifications() {
12351278
let mock_time_provider = Arc::new(MockTimeProvider::new(1000));
@@ -1306,51 +1349,26 @@ fn dos_protection() {
13061349

13071350
let client_handler = client_node.liquidity_manager.lsps5_client_handler().unwrap();
13081351

1309-
let assert_reject = || -> () {
1310-
let _ = client_handler
1311-
.set_webhook(
1312-
service_node_id,
1313-
"App".to_string(),
1314-
"https://example.org/webhook".to_string(),
1315-
)
1316-
.expect("Request should send");
1317-
let request = get_lsps_message!(client_node, service_node_id);
1318-
1319-
let result = service_node.liquidity_manager.handle_custom_message(request, client_node_id);
1320-
assert!(result.is_err(), "Service should reject request without prior interaction");
1321-
1322-
assert!(service_node.liquidity_manager.get_and_clear_pending_msg().is_empty());
1323-
};
1324-
1325-
let assert_accept = || -> () {
1326-
let _ = client_handler
1327-
.set_webhook(
1328-
service_node_id,
1329-
"App".to_string(),
1330-
"https://example.org/webhook".to_string(),
1331-
)
1332-
.expect("Request should send");
1333-
let request = get_lsps_message!(client_node, service_node_id);
1334-
1335-
let result = service_node.liquidity_manager.handle_custom_message(request, client_node_id);
1336-
assert!(result.is_ok(), "Service should accept request after prior interaction");
1337-
let _ = service_node.liquidity_manager.next_event().unwrap();
1338-
let response = get_lsps_message!(service_node, client_node_id);
1339-
client_node
1340-
.liquidity_manager
1341-
.handle_custom_message(response, service_node_id)
1342-
.expect("Client should handle response");
1343-
let _ = client_node.liquidity_manager.next_event().unwrap();
1344-
};
1345-
13461352
// no channel is open so far -> should reject
1347-
assert_reject();
1353+
assert_lsps5_reject!(
1354+
client_handler,
1355+
service_node,
1356+
client_node,
1357+
service_node_id,
1358+
client_node_id
1359+
);
13481360

13491361
let (_, _, _, channel_id, funding_tx) =
13501362
create_chan_between_nodes(&service_node.inner, &client_node.inner);
13511363

13521364
// now that a channel is open, should accept
1353-
assert_accept();
1365+
assert_lsps5_accept!(
1366+
client_handler,
1367+
service_node,
1368+
client_node,
1369+
service_node_id,
1370+
client_node_id
1371+
);
13541372

13551373
close_channel(&service_node.inner, &client_node.inner, &channel_id, funding_tx, true);
13561374
let node_a_reason = ClosureReason::CounterpartyInitiatedCooperativeClosure;
@@ -1359,7 +1377,13 @@ fn dos_protection() {
13591377
check_closed_event!(client_node.inner, 1, node_b_reason, [service_node_id], 100000);
13601378

13611379
// channel is now closed again -> should reject
1362-
assert_reject();
1380+
assert_lsps5_reject!(
1381+
client_handler,
1382+
service_node,
1383+
client_node,
1384+
service_node_id,
1385+
client_node_id
1386+
);
13631387
}
13641388

13651389
#[test]
@@ -1370,20 +1394,28 @@ fn lsps2_state_allows_lsps5_request() {
13701394
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
13711395

13721396
let (lsps_nodes, _) = lsps5_lsps2_test_setup(nodes, Arc::new(DefaultTimeProvider));
1373-
establish_lsps2_prior_interaction(&lsps_nodes);
13741397

1375-
let LSPSNodes { service_node, client_node } = lsps_nodes;
1376-
let service_node_id = service_node.inner.node.get_our_node_id();
1377-
let client_node_id = client_node.inner.node.get_our_node_id();
1398+
let client_node_id = lsps_nodes.client_node.inner.node.get_our_node_id();
1399+
let service_node_id = lsps_nodes.service_node.inner.node.get_our_node_id();
1400+
let client_handler = lsps_nodes.client_node.liquidity_manager.lsps5_client_handler().unwrap();
13781401

1379-
let lsps5_client = client_node.liquidity_manager.lsps5_client_handler().unwrap();
1402+
assert_lsps5_reject!(
1403+
client_handler,
1404+
lsps_nodes.service_node,
1405+
lsps_nodes.client_node,
1406+
service_node_id,
1407+
client_node_id
1408+
);
13801409

1381-
let _ = lsps5_client
1382-
.set_webhook(service_node_id, "App".to_string(), "https://example.org/webhook".to_string())
1383-
.expect("Request should send");
1384-
let request = get_lsps_message!(client_node, service_node_id);
1385-
let result = service_node.liquidity_manager.handle_custom_message(request, client_node_id);
1386-
assert!(result.is_ok(), "Service should accept request based on LSPS2 state");
1410+
establish_lsps2_prior_interaction(&lsps_nodes);
1411+
1412+
assert_lsps5_accept!(
1413+
client_handler,
1414+
lsps_nodes.service_node,
1415+
lsps_nodes.client_node,
1416+
service_node_id,
1417+
client_node_id
1418+
);
13871419
}
13881420

13891421
fn establish_lsps2_prior_interaction(lsps_nodes: &LSPSNodes) {

0 commit comments

Comments
 (0)