plugin: lsps: simplify json-rpc response object
What changed, and why it matters
This commit is a routine internal code cleanup in Core Lightning's experimental LSPS plugin. It replaces one Rust programming pattern for building JSON-RPC response messages with another, more idiomatic pattern. There is no indication it fixes a security bug, changes wire behavior, or introduces a vulnerability. It is purely a refactor.
No security action required. Treat as normal code maintenance. Reviewers may optionally verify that the new manual Serialize/Deserialize implementations still produce byte-identical JSON-RPC 2.0 output for success and error responses.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors the LSPS plugin’s JSON-RPC response handling. It removes the blanket JsonRpcResponse trait and ResponseObject<T> struct and introduces an explicit JsonRpcResponse<R> struct plus a JsonRpcResponseBody<R> enum. Serialization/deserialization are now implemented manually to preserve the same JSON-RPC 2.0 wire format. All call sites are updated to use JsonRpcResponse::success(...) and JsonRpcResponse::error(...) constructors and into_result() accessors. The commit also fixes a minor type mismatch in service.rs where LspsResponseWriter::write now returns the plugin’s own Error type instead of JError. No security-relevant behavior changes are visible in the diff.
Changed components
plugins/lsps-plugin/src/proto/jsonrpc.rsplugins/lsps-plugin/src/jsonrpc/client.rsplugins/lsps-plugin/src/jsonrpc/server.rsplugins/lsps-plugin/src/lsps0/handler.rsplugins/lsps-plugin/src/lsps2/handler.rsplugins/lsps-plugin/src/service.rsInspect captured patch +250 / −164
diff --git a/plugins/lsps-plugin/src/jsonrpc/client.rs b/plugins/lsps-plugin/src/jsonrpc/client.rs
index 350d815c..6eaad51c 100644
--- a/plugins/lsps-plugin/src/jsonrpc/client.rs
+++ b/plugins/lsps-plugin/src/jsonrpc/client.rs
@@ -1,5 +1,5 @@
use crate::proto::jsonrpc::{
- Error as JsonRpcError, JsonRpcRequest, JsonRpcResponse, RequestObject, ResponseObject,
+ Error as JsonRpcError, JsonRpcRequest, JsonRpcResponse, RequestObject,
};
use async_trait::async_trait;
use core::fmt::Debug;
@@ -36,6 +36,14 @@ impl From<serde_json::Error> for Error {
pub type Result<T> = std::result::Result<T, Error>;
+impl<R> From<JsonRpcResponse<R>> for Result<R> {
+ fn from(value: JsonRpcResponse<R>) -> Self {
+ value
+ .into_result()
+ .map_err(|e| Error::JsonRpcError(JsonRpcError::RpcError(e)))
+ }
+}
+
/// Defines the interface for transporting JSON-RPC messages.
///
/// Implementors of this trait are responsible for actually sending the JSON-RPC
@@ -74,8 +82,9 @@ impl<T: Transport> JsonRpcClient<T> {
params,
id: Some(id.clone().into()),
};
- let res_obj = self.send_request(method, &request, id).await?;
- Ok(Value::from_response(res_obj)?)
+
+ let response: JsonRpcResponse<Value> = self.send_request(method, &request, id).await?;
+ response.into()
}
/// Makes a typed JSON-RPC method call with a request object and returns a
@@ -93,8 +102,8 @@ impl<T: Transport> JsonRpcClient<T> {
debug!("Preparing request: method={}, id={}", method, id);
let request = request.into_request(Some(id.clone().into()));
- let res_obj = self.send_request(method, &request, id).await?;
- Ok(RS::from_response(res_obj)?)
+ let response: JsonRpcResponse<RS> = self.send_request(method, &request, id).await?;
+ response.into()
}
/// Sends a notification with raw JSON parameters (no response expected).
@@ -126,7 +135,7 @@ impl<T: Transport> JsonRpcClient<T> {
method: &str,
payload: &RP,
id: String,
- ) -> Result<ResponseObject<RS>>
+ ) -> Result<JsonRpcResponse<RS>>
where
RP: Serialize + Send + Sync,
RS: DeserializeOwned + Serialize + Debug + Send + Sync,
@@ -274,9 +283,7 @@ mod test_json_rpc {
bar: 10,
};
- let res_obj = expected_res
- .clone()
- .into_response(String::from("unique-id-123"));
+ let res_obj = JsonRpcResponse::success(&expected_res, "my-id-123");
let res_str = serde_json::to_string(&res_obj).unwrap();
let transport = TestTransport {
@@ -323,7 +330,7 @@ mod test_json_rpc {
serde_json::json!({"got": "some"}),
);
- let res_obj = err_res.clone().into_response("unique-id-123".into());
+ let res_obj = JsonRpcResponse::error(err_res, "unique-id-123");
let res_str = serde_json::to_string(&res_obj).unwrap();
let transport = TestTransport {
diff --git a/plugins/lsps-plugin/src/jsonrpc/server.rs b/plugins/lsps-plugin/src/jsonrpc/server.rs
index 922a4c25..f0ebdbb4 100644
--- a/plugins/lsps-plugin/src/jsonrpc/server.rs
+++ b/plugins/lsps-plugin/src/jsonrpc/server.rs
@@ -1,4 +1,5 @@
-use crate::proto::jsonrpc::{Result, RpcError};
+use crate::proto::jsonrpc::RpcError;
+use crate::{jsonrpc::client::Result, proto::jsonrpc::JsonRpcResponse};
use async_trait::async_trait;
use log::{debug, trace};
use std::{collections::HashMap, sync::Arc};
@@ -155,7 +156,7 @@ impl JsonRpcServer {
) -> Result<()> {
// No need to respond when we don't have an id - it's a notification
if let Some(id) = id {
- let err_res = err.clone().into_response(id.into());
+ let err_res = JsonRpcResponse::error(err, id);
let err_vec = serde_json::to_vec(&err_res)?;
return writer.write(&err_vec).await;
}
diff --git a/plugins/lsps-plugin/src/lsps0/handler.rs b/plugins/lsps-plugin/src/lsps0/handler.rs
index ebdc13e0..e6a5a838 100644
--- a/plugins/lsps-plugin/src/lsps0/handler.rs
+++ b/plugins/lsps-plugin/src/lsps0/handler.rs
@@ -1,7 +1,7 @@
use crate::{
jsonrpc::server::RequestHandler,
proto::{
- jsonrpc::{JsonRpcResponse as _, RequestObject, RpcError},
+ jsonrpc::{JsonRpcResponse, RequestObject, RpcError},
lsps0::{Lsps0listProtocolsRequest, Lsps0listProtocolsResponse},
},
util::unwrap_payload_with_peer_id,
@@ -24,7 +24,7 @@ impl RequestHandler for Lsps0ListProtocolsHandler {
if self.lsps2_enabled {
protocols.push(2);
}
- let res = Lsps0listProtocolsResponse { protocols }.into_response(id);
+ let res = JsonRpcResponse::success(Lsps0listProtocolsResponse { protocols }, id);
let res_vec = serde_json::to_vec(&res).unwrap();
return Ok(res_vec);
}
@@ -36,10 +36,7 @@ impl RequestHandler for Lsps0ListProtocolsHandler {
#[cfg(test)]
mod test {
use super::*;
- use crate::{
- proto::jsonrpc::{JsonRpcRequest as _, ResponseObject},
- util::wrap_payload_with_peer_id,
- };
+ use crate::{proto::jsonrpc::JsonRpcRequest as _, util::wrap_payload_with_peer_id};
use cln_rpc::primitives::PublicKey;
const PUBKEY: [u8; 33] = [
@@ -67,10 +64,10 @@ mod test {
let payload = create_wrapped_request(&request);
let result = handler.handle(&payload).await.unwrap();
- let response: ResponseObject<Lsps0listProtocolsResponse> =
+ let response: JsonRpcResponse<Lsps0listProtocolsResponse> =
serde_json::from_slice(&result).unwrap();
- let data = response.into_inner().expect("Should have result data");
+ let data = response.into_result().expect("Should have result data");
assert!(data.protocols.is_empty());
}
@@ -84,10 +81,10 @@ mod test {
let payload = create_wrapped_request(&request);
let result = handler.handle(&payload).await.unwrap();
- let response: ResponseObject<Lsps0listProtocolsResponse> =
+ let response: JsonRpcResponse<Lsps0listProtocolsResponse> =
serde_json::from_slice(&result).unwrap();
- let data = response.into_inner().expect("Should have result data");
+ let data = response.into_result().expect("Should have result data");
assert_eq!(data.protocols, vec![2]);
}
}
diff --git a/plugins/lsps-plugin/src/lsps2/handler.rs b/plugins/lsps-plugin/src/lsps2/handler.rs
index 4624bbc3..250fd8b0 100644
--- a/plugins/lsps-plugin/src/lsps2/handler.rs
+++ b/plugins/lsps-plugin/src/lsps2/handler.rs
@@ -239,10 +239,12 @@ impl<T: ClnApi + 'static> RequestHandler for Lsps2GetInfoHandler<T> {
})
.collect::<Result<Vec<_>, RpcError>>()?;
- let res = Lsps2GetInfoResponse {
- opening_fee_params_menu,
- }
- .into_response(req.id.unwrap()); // We checked that we got an id before.
+ let res = JsonRpcResponse::success(
+ Lsps2GetInfoResponse {
+ opening_fee_params_menu,
+ },
+ req.id.unwrap(),
+ ); // We checked that we got an id before.
serde_json::to_vec(&res)
.map_err(|e| RpcError::internal_error(format!("Failed to serialize response: {}", e)))
@@ -325,15 +327,17 @@ impl<A: ClnApi + 'static> RequestHandler for Lsps2BuyHandler<A> {
RpcError::internal_error("Internal error")
})?;
- let res = Lsps2BuyResponse {
- jit_channel_scid: jit_scid,
- // We can make this configurable if necessary.
- lsp_cltv_expiry_delta: DEFAULT_CLTV_EXPIRY_DELTA,
- // We can implement the other mode later on as we might have to do
- // some additional work on core-lightning to enable this.
- client_trusts_lsp: false,
- }
- .into_response(req.id.unwrap()); // We checked that we got an id before.
+ let res = JsonRpcResponse::success(
+ Lsps2BuyResponse {
+ jit_channel_scid: jit_scid,
+ // We can make this configurable if necessary.
+ lsp_cltv_expiry_delta: DEFAULT_CLTV_EXPIRY_DELTA,
+ // We can implement the other mode later on as we might have to do
+ // some additional work on core-lightning to enable this.
+ client_trusts_lsp: false,
+ },
+ req.id.unwrap(),
+ ); // We checked that we got an id before.
serde_json::to_vec(&res)
.map_err(|e| RpcError::internal_error(format!("Failed to serialize response: {}", e)))
@@ -682,11 +686,7 @@ mod tests {
use super::*;
use crate::{
lsps2::cln::{tlv::TlvStream, HtlcAcceptedResult},
- proto::{
- jsonrpc::{JsonRpcRequest, ResponseObject},
- lsps0::Ppm,
- lsps2::PolicyOpeningFeeParams,
- },
+ proto::{jsonrpc::JsonRpcRequest, lsps0::Ppm, lsps2::PolicyOpeningFeeParams},
util::wrap_payload_with_peer_id,
};
use chrono::{TimeZone, Utc};
@@ -1026,9 +1026,9 @@ mod tests {
let payload = create_wrapped_request(&request);
let result = handler.handle(&payload).await.unwrap();
- let response: ResponseObject<Lsps2GetInfoResponse> =
+ let response: JsonRpcResponse<Lsps2GetInfoResponse> =
serde_json::from_slice(&result).unwrap();
- let response = response.into_inner().unwrap();
+ let response = response.into_result().unwrap();
assert_eq!(
response.opening_fee_params_menu[0].min_payment_size_msat,
@@ -1088,8 +1088,8 @@ mod tests {
let payload = create_wrapped_request(&req);
let out = handler.handle(&payload).await.unwrap();
- let resp: ResponseObject<Lsps2BuyResponse> = serde_json::from_slice(&out).unwrap();
- let resp = resp.into_inner().unwrap();
+ let resp: JsonRpcResponse<Lsps2BuyResponse> = serde_json::from_slice(&out).unwrap();
+ let resp = resp.into_result().unwrap();
assert_eq!(resp.lsp_cltv_expiry_delta, DEFAULT_CLTV_EXPIRY_DELTA);
assert!(!resp.client_trusts_lsp);
@@ -1120,8 +1120,8 @@ mod tests {
let payload = create_wrapped_request(&req);
let out = handler.handle(&payload).await.unwrap();
- let resp: ResponseObject<Lsps2BuyResponse> = serde_json::from_slice(&out).unwrap();
- assert!(resp.into_inner().is_ok());
+ let resp: JsonRpcResponse<Lsps2BuyResponse> = serde_json::from_slice(&out).unwrap();
+ assert!(resp.into_result().is_ok());
}
#[tokio::test]
diff --git a/plugins/lsps-plugin/src/proto/jsonrpc.rs b/plugins/lsps-plugin/src/proto/jsonrpc.rs
index ef4c6c9f..b403312f 100644
--- a/plugins/lsps-plugin/src/proto/jsonrpc.rs
+++ b/plugins/lsps-plugin/src/proto/jsonrpc.rs
@@ -65,43 +65,6 @@ pub trait JsonRpcRequest: Serialize {
}
}
-/// Trait for types that can be converted from JSON-RPC response objects.
-///
-/// This trait provides methods for converting between typed response objects
-/// and JSON-RPC protocol response envelopes.
-pub trait JsonRpcResponse<T>
-where
- T: DeserializeOwned,
-{
- fn into_response(self, id: String) -> ResponseObject<Self>
- where
- Self: Sized + DeserializeOwned,
- {
- ResponseObject {
- jsonrpc: "2.0".into(),
- id: id.into(),
- result: Some(self),
- error: None,
- }
- }
-
- fn from_response(resp: ResponseObject<T>) -> Result<T>
- where
- T: core::fmt::Debug,
- {
- match (resp.result, resp.error) {
- (Some(result), None) => Ok(result),
- (None, Some(error)) => Err(Error::RpcError(error)),
- _ => Err(Error::ParseResponse),
- }
- }
-}
-
-/// Automatically implements the `JsonRpcResponse` trait for all types that
-/// implement `DeserializeOwned`. This simplifies creating JSON-RPC services,
-/// as you only need to define data structures that can be deserialized.
-impl<T> JsonRpcResponse<T> for T where T: DeserializeOwned {}
-
/// # RequestObject
///
/// Represents a JSON-RPC 2.0 Request object, as defined in section 4 of the
@@ -154,44 +117,182 @@ fn is_none_or_null<T: Serialize>(opt: &Option<T>) -> bool {
}
}
-/// # ResponseObject
-///
-/// Represents a JSON-RPC 2.0 Response object, as defined in section 5.0 of the
-/// specification. This structure encapsulates either a successful result or
-/// an error.
-///
-/// # Type Parameters
-///
-/// * `T`: The type of the `result` field, which will be returned upon a
-/// succesful execution of the procedure. *MUST* implement both `Serialize`
-/// (to allow construction of responses) and `DeserializeOwned` (to allow
-/// receipt and parsing of responses).
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(bound = "T: Serialize + DeserializeOwned")]
-pub struct ResponseObject<T>
-where
- T: DeserializeOwned,
-{
- /// **REQUIRED**. MUST be `"2.0"`.
- jsonrpc: String,
- /// **REQUIRED**. The identifier of the original request this is a response.
+pub struct JsonRpcResponse<R = ()> {
id: String,
- /// **REQUIRED on success**. The data if there is a request and non-errored.
- /// MUST NOT exist if there was an error triggered during invocation.
- #[serde(skip_serializing_if = "Option::is_none")]
- result: Option<T>,
- /// **REQUIRED on error** An error type if there was a failure.
- error: Option<RpcError>,
+ body: JsonRpcResponseBody<R>,
}
-impl<T> ResponseObject<T>
-where
- T: DeserializeOwned + Serialize + core::fmt::Debug,
-{
- /// Returns a potential data (result) if the code execution passed else it
- /// returns with RPC error, data (error details) if there was
- pub fn into_inner(self) -> Result<T> {
- T::from_response(self)
+impl JsonRpcResponse<()> {
+ pub fn error<T: Into<String>>(error: RpcError, id: T) -> Self {
+ Self {
+ id: id.into(),
+ body: JsonRpcResponseBody::Error { error },
+ }
+ }
+}
+
+impl<R> JsonRpcResponse<R> {
+ pub fn success<T: Into<String>>(result: R, id: T) -> Self {
+ Self {
+ id: id.into(),
+ body: JsonRpcResponseBody::Success { result },
+ }
+ }
+
+ pub fn into_result(self) -> std::result::Result<R, RpcError> {
+ self.body.into_result()
+ }
+
+ pub fn as_result(&self) -> std::result::Result<&R, &RpcError> {
+ self.body.as_result()
+ }
+
+ pub fn is_ok(&self) -> bool {
+ self.body.is_ok()
+ }
+
+ pub fn is_err(&self) -> bool {
+ self.body.is_err()
+ }
+
+ pub fn map<U, F>(self, f: F) -> JsonRpcResponse<U>
+ where
+ F: FnOnce(R) -> U,
+ {
+ JsonRpcResponse {
+ id: self.id,
+ body: self.body.map(f),
+ }
+ }
+
+ /// Unwrap the result, panicking on RPC error
+ pub fn unwrap(self) -> R {
+ self.body.unwrap()
+ }
+
+ /// Expect success or panic with message
+ pub fn expect(self, msg: &str) -> R {
+ self.body.expect(msg)
+ }
+}
+
+// Custom Serialize to match JSON-RPC 2.0 wire format
+impl<R: Serialize> Serialize for JsonRpcResponse<R> {
+ fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ use serde::ser::SerializeStruct;
+
+ let mut state = serializer.serialize_struct("JsonRpcResponse", 3)?;
+ state.serialize_field("jsonrpc", "2.0")?;
+ state.serialize_field("id", &self.id)?;
+
+ match &self.body {
+ JsonRpcResponseBody::Success { result } => {
+ state.serialize_field("result", result)?;
+ }
+ JsonRpcResponseBody::Error { error } => {
+ state.serialize_field("error", error)?;
+ }
+ }
+
+ state.end()
+ }
+}
+
+// Custom Deserialize from JSON-RPC 2.0 wire format
+impl<'de, R: DeserializeOwned> Deserialize<'de> for JsonRpcResponse<R> {
+ fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ #[derive(Deserialize)]
+ struct RawResponse<R> {
+ jsonrpc: String,
+ result: Option<R>,
+ error: Option<RpcError>,
+ id: String,
+ }
+
+ let raw = RawResponse::deserialize(deserializer)?;
+
+ if raw.jsonrpc != "2.0" {
+ return Err(serde::de::Error::custom(format!(
+ "Invalid JSON-RPC version: {}",
+ raw.jsonrpc
+ )));
+ }
+
+ let body = match (raw.result, raw.error) {
+ (Some(result), None) => JsonRpcResponseBody::Success { result },
+ (None, Some(error)) => JsonRpcResponseBody::Error { error },
+ (Some(_), Some(_)) => {
+ return Err(serde::de::Error::custom(
+ "Response cannot have both result and error",
+ ))
+ }
+ (None, None) => {
+ return Err(serde::de::Error::custom(
+ "Response must have either result or error",
+ ))
+ }
+ };
+
+ Ok(JsonRpcResponse { id: raw.id, body })
+ }
+}
+
+pub enum JsonRpcResponseBody<R> {
+ Success { result: R },
+ Error { error: RpcError },
+}
+
+impl<R> JsonRpcResponseBody<R> {
+ pub fn into_result(self) -> std::result::Result<R, RpcError> {
+ match self {
+ Self::Success { result } => Ok(result),
+ Self::Error { error } => Err(error),
+ }
+ }
+
+ pub fn as_result(&self) -> std::result::Result<&R, &RpcError> {
+ match self {
+ Self::Success { result } => Ok(result),
+ Self::Error { error } => Err(error),
+ }
+ }
+
+ pub fn is_ok(&self) -> bool {
+ matches!(self, JsonRpcResponseBody::Success { .. })
+ }
+
+ pub fn is_err(&self) -> bool {
+ matches!(self, JsonRpcResponseBody::Error { .. })
+ }
+
+ pub fn map<U, F>(self, f: F) -> JsonRpcResponseBody<U>
+ where
+ F: FnOnce(R) -> U,
+ {
+ match self {
+ Self::Success { result } => JsonRpcResponseBody::Success { result: f(result) },
+ Self::Error { error } => JsonRpcResponseBody::Error { error },
+ }
+ }
+
+ pub fn unwrap(self) -> R {
+ match self {
+ Self::Success { result } => result,
+ Self::Error { error } => panic!("Called unwrap on RPC Error: {}", error),
+ }
+ }
+
+ pub fn expect(self, msg: &str) -> R {
+ match self {
+ Self::Success { result } => result,
+ Self::Error { error } => panic!("{}: {}", msg, error),
+ }
}
}
@@ -244,17 +345,6 @@ pub struct RpcError {
pub data: Option<Value>,
}
-impl RpcError {
- pub fn into_response(self, id: String) -> ResponseObject<serde_json::Value> {
- ResponseObject {
- jsonrpc: "2.0".into(),
- id: id.into(),
- result: None,
- error: Some(self),
- }
- }
-}
-
impl RpcError {
/// Reserved for implementation-defined server-errors.
pub fn custom_error<T: core::fmt::Display>(code: i64, message: T) -> Self {
@@ -383,17 +473,18 @@ mod test_message_serialization {
"id": "unique-id-123"
}"#;
- let response_object: ResponseObject<SayNameResponse> =
+ let response: JsonRpcResponse<SayNameResponse> =
serde_json::from_str(json_response).unwrap();
- let response: SayNameResponse = response_object.into_inner().unwrap();
- let expected_response = SayNameResponse {
- name: "Satoshi".into(),
- age: 99,
- message: "Hello Satoshi!".into(),
- };
-
- assert_eq!(response, expected_response);
+ let result = response.into_result().unwrap();
+ assert_eq!(
+ result,
+ SayNameResponse {
+ name: "Satoshi".into(),
+ age: 99,
+ message: "Hello Satoshi!".into(),
+ }
+ );
}
#[test]
@@ -409,13 +500,9 @@ mod test_message_serialization {
"id": "unique-id-123"
}"#;
- let response_object: ResponseObject<DummyResponse> =
- serde_json::from_str(json_response).unwrap();
-
- let response: DummyResponse = response_object.into_inner().unwrap();
- let expected_response = DummyResponse {};
-
- assert_eq!(response, expected_response);
+ let response: JsonRpcResponse<DummyResponse> = serde_json::from_str(json_response).unwrap();
+ let result = response.into_result().unwrap();
+ assert_eq!(result, DummyResponse {});
}
#[test]
fn test_error_deserialization() {
@@ -437,22 +524,13 @@ mod test_message_serialization {
}
}"#;
- let response_object: ResponseObject<DummyResponse> =
- serde_json::from_str(json_response).unwrap();
+ let response: JsonRpcResponse<DummyResponse> = serde_json::from_str(json_response).unwrap();
+ assert!(response.is_err());
- let response = response_object.into_inner();
- let err = response.unwrap_err();
- match err {
- Error::RpcError(err) => {
- assert_eq!(err.code, -32099);
- assert_eq!(err.message, "something bad happened");
- assert_eq!(
- err.data,
- serde_json::from_str("{\"f1\":\"v1\",\"f2\":2}").unwrap()
- );
- }
- _ => assert!(false),
- }
+ let err = response.into_result().unwrap_err();
+ assert!(matches!(err, RpcError { .. }));
+ assert_eq!(err.message, "something bad happened");
+ assert_eq!(err.data, Some(serde_json::json!({"f1":"v1","f2":2})));
}
#[test]
diff --git a/plugins/lsps-plugin/src/service.rs b/plugins/lsps-plugin/src/service.rs
index 1528a2b2..9c59c7e6 100644
--- a/plugins/lsps-plugin/src/service.rs
+++ b/plugins/lsps-plugin/src/service.rs
@@ -1,5 +1,6 @@
use anyhow::{anyhow, bail};
use async_trait::async_trait;
+use cln_lsps::jsonrpc::client::Error as CError;
use cln_lsps::jsonrpc::server::JsonRpcResponseWriter;
use cln_lsps::jsonrpc::server::JsonRpcServer;
use cln_lsps::lsps0::handler::Lsps0ListProtocolsHandler;
@@ -184,13 +185,15 @@ pub struct LspsResponseWriter {
#[async_trait]
impl JsonRpcResponseWriter for LspsResponseWriter {
- async fn write(&mut self, payload: &[u8]) -> std::result::Result<(), JError> {
+ async fn write(&mut self, payload: &[u8]) -> std::result::Result<(), CError> {
let mut client = cln_rpc::ClnRpc::new(&self.rpc_path)
.await
.map_err(|e| JError::Other(e.to_string()))?;
- transport::send_custommsg(&mut client, payload.to_vec(), self.peer_id)
- .await
- .map_err(|e| JError::Other(e.to_string()))
+ Ok(
+ transport::send_custommsg(&mut client, payload.to_vec(), self.peer_id)
+ .await
+ .map_err(|e| JError::Other(e.to_string()))?,
+ )
}
}
Why this scored 13/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.