plugins: lsps: implement ClnSender for bolt8 transport
What changed, and why it matters
This commit adds a new Rust module that lets the LSPS plugin send custom Lightning messages through Core Lightning's RPC interface. It is a straightforward feature implementation with no obvious security bug. There is no indication in the commit that it fixes a vulnerability or addresses a security issue.
No security action required based on this commit alone. Review the LSPS0 framing and RPC error handling as part of normal code review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces ClnSender, an implementation of the MessageSender trait that wraps cln_rpc::ClnRpc and calls sendcustommsg with an LSPS0-framed payload. It adds the module to cln_adapters/mod.rs and creates sender.rs with the implementation. The code maps RPC errors to TransportError::Internal. No input validation, authentication, or cryptographic logic beyond the existing RPC call is present, and no security-relevant defect is visible in the diff.
Changed components
plugins/lsps-plugin/src/cln_adapters/sender.rsplugins/lsps-plugin/src/cln_adapters/mod.rsInspect captured patch +41 / −0
diff --git a/plugins/lsps-plugin/src/cln_adapters/mod.rs b/plugins/lsps-plugin/src/cln_adapters/mod.rs
index 5427a919..2aa0c761 100644
--- a/plugins/lsps-plugin/src/cln_adapters/mod.rs
+++ b/plugins/lsps-plugin/src/cln_adapters/mod.rs
@@ -1,2 +1,3 @@
+pub mod sender;
pub mod service;
pub mod transport;
diff --git a/plugins/lsps-plugin/src/cln_adapters/sender.rs b/plugins/lsps-plugin/src/cln_adapters/sender.rs
new file mode 100644
index 00000000..236412b0
--- /dev/null
+++ b/plugins/lsps-plugin/src/cln_adapters/sender.rs
@@ -0,0 +1,40 @@
+use crate::{
+ cln_adapters::utils::encode_lsps0_frame_hex,
+ core::transport::{Error as TransportError, MessageSender},
+};
+use async_trait::async_trait;
+use bitcoin::secp256k1::PublicKey;
+use cln_rpc::{model::requests::SendcustommsgRequest, ClnRpc};
+use std::path::PathBuf;
+
+#[derive(Clone)]
+pub struct ClnSender {
+ rpc_path: PathBuf,
+}
+
+impl ClnSender {
+ pub fn new(rpc_path: PathBuf) -> Self {
+ Self { rpc_path }
+ }
+}
+
+#[async_trait]
+impl MessageSender for ClnSender {
+ async fn send(&self, peer_id: &PublicKey, payload: &[u8]) -> Result<(), TransportError> {
+ let mut rpc = ClnRpc::new(&self.rpc_path)
+ .await
+ .map_err(|e| TransportError::Internal(e.to_string()))?;
+
+ // Encode frame for LSPS0 Bolt8 transport.
+ let msg = encode_lsps0_frame_hex(payload);
+
+ rpc.call_typed(&SendcustommsgRequest {
+ msg,
+ node_id: peer_id.to_owned(),
+ })
+ .await
+ .map_err(|e| TransportError::Internal(e.to_string()))?;
+
+ Ok(())
+ }
+}
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.