lightning_liquidity/lsps0/
msgs.rs

1//! Message, request, and other primitive types used to implement LSPS0.
2
3use alloc::vec::Vec;
4use core::convert::TryFrom;
5
6use crate::lsps0::ser::{LSPSMessage, LSPSRequestId, LSPSResponseError};
7
8use serde::{Deserialize, Serialize};
9
10pub(crate) const LSPS0_LISTPROTOCOLS_METHOD_NAME: &str = "lsps0.list_protocols";
11
12/// A `list_protocols` request.
13///
14/// Please refer to the [bLIP-50 / LSPS0
15/// specification](https://github.com/lightning/blips/blob/master/blip-0050.md#lsps-specification-support-query)
16/// for more information.
17#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
18pub struct LSPS0ListProtocolsRequest {}
19
20/// A response to a `list_protocols` request.
21///
22/// Please refer to the [bLIP-50 / LSPS0
23/// specification](https://github.com/lightning/blips/blob/master/blip-0050.md#lsps-specification-support-query)
24/// for more information.
25#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
26pub struct LSPS0ListProtocolsResponse {
27	/// A list of supported protocols.
28	pub protocols: Vec<u16>,
29}
30
31/// An bLIP-50 / LSPS0 protocol request.
32///
33/// Please refer to the [bLIP-50 / LSPS0
34/// specification](https://github.com/lightning/blips/blob/master/blip-0050.md#lsps-specification-support-query)
35/// for more information.
36#[derive(Clone, Debug, PartialEq, Eq)]
37pub enum LSPS0Request {
38	/// A request calling `list_protocols`.
39	ListProtocols(LSPS0ListProtocolsRequest),
40}
41
42impl LSPS0Request {
43	/// Returns the method name associated with the given request variant.
44	pub fn method(&self) -> &'static str {
45		match self {
46			LSPS0Request::ListProtocols(_) => LSPS0_LISTPROTOCOLS_METHOD_NAME,
47		}
48	}
49}
50
51/// An bLIP-50 / LSPS0 protocol request.
52///
53/// Please refer to the [bLIP-50 / LSPS0
54/// specification](https://github.com/lightning/blips/blob/master/blip-0050.md#lsps-specification-support-query)
55/// for more information.
56#[derive(Clone, Debug, PartialEq, Eq)]
57pub enum LSPS0Response {
58	/// A response to a `list_protocols` request.
59	ListProtocols(LSPS0ListProtocolsResponse),
60	/// An error response to a `list_protocols` request.
61	ListProtocolsError(LSPSResponseError),
62}
63
64/// An bLIP-50 / LSPS0 protocol message.
65///
66/// Please refer to the [bLIP-50 / LSPS0
67/// specification](https://github.com/lightning/blips/blob/master/blip-0050.md#lsps-specification-support-query)
68/// for more information.
69#[derive(Clone, Debug, PartialEq, Eq)]
70pub enum LSPS0Message {
71	/// A request variant.
72	Request(LSPSRequestId, LSPS0Request),
73	/// A response variant.
74	Response(LSPSRequestId, LSPS0Response),
75}
76
77impl TryFrom<LSPSMessage> for LSPS0Message {
78	type Error = ();
79
80	fn try_from(message: LSPSMessage) -> Result<Self, Self::Error> {
81		match message {
82			LSPSMessage::Invalid(_) => Err(()),
83			LSPSMessage::LSPS0(message) => Ok(message),
84			LSPSMessage::LSPS1(_) => Err(()),
85			LSPSMessage::LSPS2(_) => Err(()),
86			LSPSMessage::LSPS5(_) => Err(()),
87		}
88	}
89}
90
91impl From<LSPS0Message> for LSPSMessage {
92	fn from(message: LSPS0Message) -> Self {
93		LSPSMessage::LSPS0(message)
94	}
95}
96
97#[cfg(test)]
98mod tests {
99	use lightning::util::hash_tables::new_hash_map;
100
101	use super::*;
102	use crate::lsps0::ser::LSPSMethod;
103
104	use alloc::string::ToString;
105
106	#[test]
107	fn deserializes_request() {
108		let json = r#"{
109			"jsonrpc": "2.0",
110			"id": "request:id:xyz123",
111			"method": "lsps0.list_protocols"
112		}"#;
113
114		let mut request_id_method_map = new_hash_map();
115
116		let msg = LSPSMessage::from_str_with_id_map(json, &mut request_id_method_map);
117		assert!(msg.is_ok());
118		let msg = msg.unwrap();
119		assert_eq!(
120			msg,
121			LSPSMessage::LSPS0(LSPS0Message::Request(
122				LSPSRequestId("request:id:xyz123".to_string()),
123				LSPS0Request::ListProtocols(LSPS0ListProtocolsRequest {})
124			))
125		);
126	}
127
128	#[test]
129	fn serializes_request() {
130		let request = LSPSMessage::LSPS0(LSPS0Message::Request(
131			LSPSRequestId("request:id:xyz123".to_string()),
132			LSPS0Request::ListProtocols(LSPS0ListProtocolsRequest {}),
133		));
134		let json = serde_json::to_string(&request).unwrap();
135		assert_eq!(
136			json,
137			r#"{"jsonrpc":"2.0","id":"request:id:xyz123","method":"lsps0.list_protocols","params":{}}"#
138		);
139	}
140
141	#[test]
142	fn deserializes_success_response() {
143		let json = r#"{
144	        "jsonrpc": "2.0",
145	        "id": "request:id:xyz123",
146	        "result": {
147	            "protocols": [1,2,3]
148	        }
149	    }"#;
150		let mut request_id_to_method_map = new_hash_map();
151		request_id_to_method_map
152			.insert(LSPSRequestId("request:id:xyz123".to_string()), LSPSMethod::LSPS0ListProtocols);
153
154		let response =
155			LSPSMessage::from_str_with_id_map(json, &mut request_id_to_method_map).unwrap();
156
157		assert_eq!(
158			response,
159			LSPSMessage::LSPS0(LSPS0Message::Response(
160				LSPSRequestId("request:id:xyz123".to_string()),
161				LSPS0Response::ListProtocols(LSPS0ListProtocolsResponse {
162					protocols: vec![1, 2, 3]
163				})
164			))
165		);
166	}
167
168	#[test]
169	fn deserializes_error_response() {
170		let json = r#"{
171	        "jsonrpc": "2.0",
172	        "id": "request:id:xyz123",
173	        "error": {
174	            "code": -32617,
175				"message": "Unknown Error"
176	        }
177	    }"#;
178		let mut request_id_to_method_map = new_hash_map();
179		request_id_to_method_map
180			.insert(LSPSRequestId("request:id:xyz123".to_string()), LSPSMethod::LSPS0ListProtocols);
181
182		let response =
183			LSPSMessage::from_str_with_id_map(json, &mut request_id_to_method_map).unwrap();
184
185		assert_eq!(
186			response,
187			LSPSMessage::LSPS0(LSPS0Message::Response(
188				LSPSRequestId("request:id:xyz123".to_string()),
189				LSPS0Response::ListProtocolsError(LSPSResponseError {
190					code: -32617,
191					message: "Unknown Error".to_string(),
192					data: None
193				})
194			))
195		);
196	}
197
198	#[test]
199	fn deserialize_fails_with_unknown_request_id() {
200		let json = r#"{
201	        "jsonrpc": "2.0",
202	        "id": "request:id:xyz124",
203	        "result": {
204	            "protocols": [1,2,3]
205	        }
206	    }"#;
207		let mut request_id_to_method_map = new_hash_map();
208		request_id_to_method_map
209			.insert(LSPSRequestId("request:id:xyz123".to_string()), LSPSMethod::LSPS0ListProtocols);
210
211		let response = LSPSMessage::from_str_with_id_map(json, &mut request_id_to_method_map);
212		assert!(response.is_err());
213	}
214
215	#[test]
216	fn serializes_response() {
217		let response = LSPSMessage::LSPS0(LSPS0Message::Response(
218			LSPSRequestId("request:id:xyz123".to_string()),
219			LSPS0Response::ListProtocols(LSPS0ListProtocolsResponse { protocols: vec![1, 2, 3] }),
220		));
221		let json = serde_json::to_string(&response).unwrap();
222		assert_eq!(
223			json,
224			r#"{"jsonrpc":"2.0","id":"request:id:xyz123","result":{"protocols":[1,2,3]}}"#
225		);
226	}
227}