Skip to content

Commit dda85fa

Browse files
committed
lsp_plugin: relax LSP feateture bit handling
Replace ensure_lsp_connected() by check_peer_lsp_status() which only returns the status of the peer (connected, has_lsp_feature). This allows us to be more tolearant about the LSP feature bit since it is only optional according to the spec. We still check for the feature but only return a warning in the logs. Signed-off-by: Peter Neuroth <pet.v.ne@gmail.com>
1 parent 6012551 commit dda85fa

1 file changed

Lines changed: 73 additions & 39 deletions

File tree

plugins/lsps-plugin/src/client.rs

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{anyhow, Context};
1+
use anyhow::{anyhow, bail, Context};
22
use chrono::{Duration, Utc};
33
use cln_lsps::jsonrpc::client::JsonRpcClient;
44
use cln_lsps::lsps0::primitives::Msat;
@@ -112,9 +112,19 @@ async fn on_lsps_lsps2_getinfo(
112112
let rpc_path = Path::new(&dir).join(&p.configuration().rpc_file);
113113
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
114114

115-
// Fail early: Check that we are connected to the peer and that it has the
116-
// LSP feature bit set.
117-
ensure_lsp_connected(&mut cln_client, &req.lsp_id).await?;
115+
let lsp_status = check_peer_lsp_status(&mut cln_client, &req.lsp_id).await?;
116+
117+
// Fail early: Check that we are connected to the peer.
118+
if !lsp_status.connected {
119+
bail!("Not connected to peer {}", &req.lsp_id);
120+
};
121+
122+
// From Blip52: LSPs MAY set the features bit numbered 729
123+
// (option_supports_lsps)...
124+
// We only log that it is not set but don't fail.
125+
if !lsp_status.has_lsp_feature {
126+
debug!("Peer {} doesn't have the LSP feature bit set.", &req.lsp_id);
127+
}
118128

119129
// Create Transport and Client
120130
let transport = Bolt8Transport::new(
@@ -153,9 +163,19 @@ async fn on_lsps_lsps2_buy(
153163
let rpc_path = Path::new(&dir).join(&p.configuration().rpc_file);
154164
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
155165

156-
// Fail early: Check that we are connected to the peer and that it has the
157-
// LSP feature bit set.
158-
ensure_lsp_connected(&mut cln_client, &req.lsp_id).await?;
166+
let lsp_status = check_peer_lsp_status(&mut cln_client, &req.lsp_id).await?;
167+
168+
// Fail early: Check that we are connected to the peer.
169+
if !lsp_status.connected {
170+
bail!("Not connected to peer {}", &req.lsp_id);
171+
};
172+
173+
// From Blip52: LSPs MAY set the features bit numbered 729
174+
// (option_supports_lsps)...
175+
// We only log that it is not set but don't fail.
176+
if !lsp_status.has_lsp_feature {
177+
debug!("Peer {} doesn't have the LSP feature bit set.", &req.lsp_id);
178+
}
159179

160180
// Create Transport and Client
161181
let transport = Bolt8Transport::new(
@@ -542,10 +562,19 @@ async fn on_lsps_listprotocols(
542562
let mut cln_client = cln_rpc::ClnRpc::new(rpc_path.clone()).await?;
543563

544564
let req: Request = serde_json::from_value(v).context("Failed to parse request JSON")?;
565+
let lsp_status = check_peer_lsp_status(&mut cln_client, &req.lsp_id).await?;
566+
567+
// Fail early: Check that we are connected to the peer.
568+
if !lsp_status.connected {
569+
bail!("Not connected to peer {}", &req.lsp_id);
570+
};
545571

546-
// Fail early: Check that we are connected to the peer and that it has the
547-
// LSP feature bit set.
548-
ensure_lsp_connected(&mut cln_client, &req.lsp_id).await?;
572+
// From Blip52: LSPs MAY set the features bit numbered 729
573+
// (option_supports_lsps)...
574+
// We only log that it is not set but don't fail.
575+
if !lsp_status.has_lsp_feature {
576+
debug!("Peer {} doesn't have the LSP feature bit set.", &req.lsp_id);
577+
}
549578

550579
// Create the transport first and handle potential errors
551580
let transport = Bolt8Transport::new(
@@ -563,48 +592,53 @@ async fn on_lsps_listprotocols(
563592
let res: lsps0::model::Lsps0listProtocolsResponse = client
564593
.call_typed(request)
565594
.await
566-
.context("lsps0.list_protocols call failed")?;
595+
.map_err(|e| anyhow!("lsps0.list_protocols call failed: {}", e))?;
567596

568597
debug!("Received lsps0.list_protocols response: {:?}", res);
569598
Ok(serde_json::to_value(res)?)
570599
}
571600

572-
/// Checks that the node is connected to the peer and that it has the LSP
573-
/// feature bit set.
574-
async fn ensure_lsp_connected(cln_client: &mut ClnRpc, lsp_id: &str) -> Result<(), anyhow::Error> {
601+
struct PeerLspStatus {
602+
connected: bool,
603+
has_lsp_feature: bool,
604+
}
605+
606+
/// Returns the `PeerLspStatus`, containing information about the connectivity
607+
/// and the LSP feature bit.
608+
async fn check_peer_lsp_status(
609+
cln_client: &mut ClnRpc,
610+
peer_id: &str,
611+
) -> Result<PeerLspStatus, anyhow::Error> {
575612
let res = cln_client
576613
.call_typed(&ListpeersRequest {
577-
id: Some(PublicKey::from_str(lsp_id)?),
614+
id: Some(PublicKey::from_str(peer_id)?),
578615
level: None,
579616
})
580617
.await?;
581618

582-
// unwrap in next line is safe as we checked that an item exists before.
583-
if res.peers.is_empty() || !res.peers.first().unwrap().connected {
584-
debug!("Node isn't connected to lsp {lsp_id}");
585-
return Err(anyhow!("not connected to lsp"));
586-
}
587-
588-
res.peers
589-
.first()
590-
.filter(|peer| {
591-
// Check that feature bit is set
592-
peer.features.as_deref().map_or(false, |f_str| {
593-
if let Some(feature_bits) = hex::decode(f_str).ok() {
594-
util::is_feature_bit_set_reversed(&feature_bits, LSP_FEATURE_BIT)
595-
} else {
596-
false
597-
}
619+
let peer = match res.peers.first() {
620+
None => {
621+
return Ok(PeerLspStatus {
622+
connected: false,
623+
has_lsp_feature: false,
598624
})
599-
})
600-
.ok_or_else(|| {
601-
anyhow!(
602-
"peer is not an lsp, feature bit {} is missing",
603-
LSP_FEATURE_BIT,
604-
)
605-
})?;
625+
}
626+
Some(p) => p,
627+
};
628+
629+
let connected = peer.connected;
630+
let has_lsp_feature = if let Some(f_str) = &peer.features {
631+
let feature_bits = hex::decode(f_str)
632+
.map_err(|e| anyhow!("Invalid feature bits hex for peer {peer_id}, {f_str}: {e}"))?;
633+
util::is_feature_bit_set_reversed(&feature_bits, LSP_FEATURE_BIT)
634+
} else {
635+
false
636+
};
606637

607-
Ok(())
638+
Ok(PeerLspStatus {
639+
connected,
640+
has_lsp_feature,
641+
})
608642
}
609643

610644
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

0 commit comments

Comments
 (0)