Skip to content

Commit 253d8ea

Browse files
Add LSPS5 event enums for webhook operations
- Introduce LSPS5ServiceEvent for LSPS-side webhook events including registration, listing, removal, and notification. - Define LSPS5ClientEvent for handling webhook outcomes on the client (Lightning node) side. - Outline WebhookNotificationParams enum to support notification-specific parameters. - Improve LSPS5 event documentation and field naming - Rename client/lsp fields to counterparty_node_id for consistent terminology - Replace generic String types with more specific Lsps5AppName and Lsps5WebhookUrl - Add comprehensive documentation for all events and fields - Include format specifications (UTF-8, ISO8601) and size constraints - Add request_id field to all relevant events for consistent request tracking - Provide detailed descriptions of error codes and their meanings - Use complete sentences in documentation comments
1 parent e288999 commit 253d8ea

File tree

2 files changed

+329
-1
lines changed

2 files changed

+329
-1
lines changed

lightning-liquidity/src/events/event_queue.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::LiquidityEvent;
22
use crate::sync::{Arc, Mutex};
3-
43
use alloc::collections::VecDeque;
54
use alloc::vec::Vec;
65

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
//! Contains bLIP-55 / LSPS5 event types
11+
12+
use crate::lsps0::ser::LSPSDateTime;
13+
use crate::lsps0::ser::LSPSRequestId;
14+
use alloc::string::String;
15+
use alloc::vec::Vec;
16+
use bitcoin::secp256k1::PublicKey;
17+
18+
use super::msgs::LSPS5AppName;
19+
use super::msgs::LSPS5Error;
20+
use super::msgs::LSPS5WebhookUrl;
21+
use super::msgs::WebhookNotification;
22+
23+
/// An event which an bLIP-55 / LSPS5 server should take some action in response to.
24+
#[derive(Debug, Clone, PartialEq, Eq)]
25+
pub enum LSPS5ServiceEvent {
26+
/// A notification needs to be sent to a client's webhook.
27+
///
28+
/// This event is triggered when the LSP needs to notify a client about an event
29+
/// via their registered webhook. The LSP must make an HTTP POST request to the
30+
/// provided URL with the specified headers and notification content.
31+
///
32+
/// When this event occurs, the LSP should:
33+
/// 1. Send an HTTP POST request to the specified webhook URL
34+
/// 2. Include all provided headers, especially the timestamp and signature headers
35+
/// 3. Send the JSON-serialized notification as the request body
36+
/// 4. Handle any HTTP errors according to the LSP's retry policy
37+
///
38+
/// The notification is signed using the LSP's node ID to ensure authenticity
39+
/// when received by the client. The client verifies this signature using
40+
/// [`parse_webhook_notification`], which guards against replay attacks and tampering.
41+
///
42+
/// If the HTTP request fails, the LSP may implement a retry policy according to its
43+
/// implementation preferences, but must respect rate-limiting as defined in
44+
/// [`notification_cooldown_hours`].
45+
///
46+
/// [`parse_webhook_notification`]: super::client::LSPS5ClientHandler::parse_webhook_notification
47+
/// [`notification_cooldown_hours`]: super::service::LSPS5ServiceConfig::notification_cooldown_hours
48+
SendWebhookNotification {
49+
/// Client node ID to be notified.
50+
counterparty_node_id: PublicKey,
51+
/// App name to be notified.
52+
///
53+
/// This identifies which webhook registration should be notified.
54+
///
55+
/// **Note**: The [`app_name`] must have been previously registered via [`lsps5.set_webhook`].
56+
///
57+
/// [`app_name`]: super::msgs::LSPS5AppName
58+
/// [`lsps5.set_webhook`]: super::msgs::LSPS5Request::SetWebhook
59+
app_name: LSPS5AppName,
60+
/// URL that to be contacted.
61+
///
62+
/// This is the webhook URL (HTTPS) provided by the client during registration.
63+
///
64+
/// **Note**: The URL must be a valid HTTPS URL that points to a public host.
65+
///
66+
/// [`url`]: super::msgs::LSPS5WebhookUrl
67+
url: LSPS5WebhookUrl,
68+
/// Notification method with its parameters.
69+
///
70+
/// This contains the type of notification and any associated data to be sent to the client.
71+
notification: WebhookNotification,
72+
/// Timestamp of the notification.
73+
///
74+
/// This timestamp is used for signing the notification and must be within 10 minutes
75+
/// of the client's local time for the signature to be accepted.
76+
timestamp: LSPSDateTime,
77+
/// Signature of the notification using the LSP's node ID.
78+
///
79+
/// This signature helps the client verify that the notification was sent by the LSP.
80+
signature: String,
81+
/// Headers to be included in the HTTP POST request.
82+
///
83+
/// Headers should include:
84+
/// - Content-Type (application/json)
85+
/// - x-lsps5-timestamp (timestamp in RFC3339 format, e.g., "YYYY-MM-DDThh:mm:ss.uuuZ")
86+
/// - x-lsps5-signature (signature of the notification using the LSP's node ID)
87+
headers: Vec<(String, String)>,
88+
},
89+
}
90+
91+
/// An event which an LSPS5 client should take some action in response to.
92+
#[derive(Debug, Clone, PartialEq, Eq)]
93+
pub enum LSPS5ClientEvent {
94+
/// A webhook was successfully registered with the LSP.
95+
///
96+
/// This event is triggered when the LSP confirms successful registration
97+
/// of a webhook via [`lsps5.set_webhook`]. The client has received a successful
98+
/// response with information about the total number of webhooks registered and limits.
99+
///
100+
/// When this event occurs, the client should:
101+
/// 1. Update any UI to reflect the successful registration
102+
/// 2. Store the webhook registration details if needed locally
103+
/// 3. Prepare to receive notifications at the registered webhook URL
104+
/// 4. Note that if `no_change` is `true`, the LSP did not send a test notification
105+
///
106+
/// The [`app_name`] and [`url`] both must respect maximum lengths of
107+
/// [`MAX_APP_NAME_LENGTH`] and [`MAX_WEBHOOK_URL_LENGTH`] respectively, and the
108+
/// [`url`] must use HTTPS.
109+
///
110+
/// [`lsps5.set_webhook`]: super::msgs::LSPS5Request::SetWebhook
111+
/// [`app_name`]: super::msgs::LSPS5AppName
112+
/// [`url`]: super::msgs::LSPS5WebhookUrl
113+
/// [`MAX_APP_NAME_LENGTH`]: super::msgs::MAX_APP_NAME_LENGTH
114+
/// [`MAX_WEBHOOK_URL_LENGTH`]: super::msgs::MAX_WEBHOOK_URL_LENGTH
115+
WebhookRegistered {
116+
/// The node id of the LSP that confirmed the registration.
117+
counterparty_node_id: PublicKey,
118+
/// Current number of webhooks registered for this client.
119+
num_webhooks: u32,
120+
/// Maximum number of webhooks allowed by LSP.
121+
max_webhooks: u32,
122+
/// Whether this was an unchanged registration (same app_name and URL).
123+
/// If true, the LSP didn't send a webhook notification for this registration.
124+
no_change: bool,
125+
/// The app name that was registered.
126+
app_name: LSPS5AppName,
127+
/// The webhook URL that was registered.
128+
url: LSPS5WebhookUrl,
129+
/// The identifier of the issued bLIP-55 / LSPS5 webhook registration request.
130+
///
131+
/// This can be used to track which request this event corresponds to.
132+
request_id: LSPSRequestId,
133+
},
134+
135+
/// A webhook registration attempt failed.
136+
///
137+
/// This event is triggered when the LSP rejects a webhook registration
138+
/// via [`lsps5.set_webhook`]. This failure can occur for several reasons:
139+
///
140+
/// When this event occurs, the client should:
141+
/// 1. Present an appropriate error message to the user
142+
/// 2. Consider retry strategies based on the specific error
143+
/// 3. If the error is due to reaching webhook limits, prompt the user to remove
144+
/// unused webhooks before trying again
145+
///
146+
/// Common error cases include:
147+
/// - The [`app_name`] exceeds [`MAX_APP_NAME_LENGTH`] (error [`AppNameTooLong`])
148+
/// - The [`url`] exceeds [`MAX_WEBHOOK_URL_LENGTH`] (error [`WebhookUrlTooLong`])
149+
/// - The [`url`] uses an unsupported protocol; HTTPS is required (error [`UnsupportedProtocol`])
150+
/// - Maximum number of webhooks per client has been reached (error [`TooManyWebhooks`])
151+
///
152+
/// [`lsps5.set_webhook`]: super::msgs::LSPS5Request::SetWebhook
153+
/// [`app_name`]: super::msgs::LSPS5AppName
154+
/// [`url`]: super::msgs::LSPS5WebhookUrl
155+
/// [`MAX_APP_NAME_LENGTH`]: super::msgs::MAX_APP_NAME_LENGTH
156+
/// [`MAX_WEBHOOK_URL_LENGTH`]: super::msgs::MAX_WEBHOOK_URL_LENGTH
157+
/// [`AppNameTooLong`]: super::msgs::LSPS5ProtocolError::AppNameTooLong
158+
/// [`WebhookUrlTooLong`]: super::msgs::LSPS5ProtocolError::WebhookUrlTooLong
159+
/// [`UnsupportedProtocol`]: super::msgs::LSPS5ProtocolError::UnsupportedProtocol
160+
/// [`TooManyWebhooks`]: super::msgs::LSPS5ProtocolError::TooManyWebhooks
161+
WebhookRegistrationFailed {
162+
/// The node id of the LSP that rejected the registration.
163+
counterparty_node_id: PublicKey,
164+
/// Error from the LSP.
165+
error: LSPS5Error,
166+
/// The app name that was attempted.
167+
app_name: LSPS5AppName,
168+
/// The webhook URL that was attempted.
169+
url: LSPS5WebhookUrl,
170+
/// The identifier of the issued bLIP-55 / LSPS5 webhook registration request.
171+
///
172+
/// This can be used to track which request this event corresponds to.
173+
request_id: LSPSRequestId,
174+
},
175+
176+
/// The list of registered webhooks was successfully retrieved.
177+
///
178+
/// This event is triggered when the LSP responds to a
179+
/// [`lsps5.list_webhooks`] request. The client now has an up-to-date
180+
/// list of all registered webhook app names.
181+
///
182+
/// When this event occurs, the client should:
183+
/// 1. Update any UI to display the list of registered webhooks
184+
/// 2. Update any local cache or state about registered webhooks
185+
/// 3. Check if the number of webhooks approaches the maximum allowed limit
186+
///
187+
/// This listing only provides the app names; to get the URLs, the client would
188+
/// need to maintain its own records from registration events.
189+
///
190+
/// [`lsps5.list_webhooks`]: super::msgs::LSPS5Request::ListWebhooks
191+
WebhooksListed {
192+
/// The node id of the LSP that provided the list.
193+
counterparty_node_id: PublicKey,
194+
/// List of app names with registered webhooks.
195+
app_names: Vec<LSPS5AppName>,
196+
/// Maximum number of webhooks allowed by LSP.
197+
max_webhooks: u32,
198+
/// The identifier of the issued bLIP-55 / LSPS5 list webhooks request.
199+
///
200+
/// This can be used to track which request this event corresponds to.
201+
request_id: LSPSRequestId,
202+
},
203+
204+
/// The attempt to list webhooks failed.
205+
///
206+
/// This event is triggered when the LSP rejects a
207+
/// [`lsps5.list_webhooks`] request. This is uncommon but might occur
208+
/// due to temporary server issues or authentication problems.
209+
///
210+
/// When this event occurs, the client should:
211+
/// 1. Present an appropriate error message to the user
212+
/// 2. Consider implementing a retry mechanism with backoff
213+
/// 3. If persistent, check connectivity to the LSP node
214+
///
215+
/// The error details provided can help diagnose the specific issue.
216+
///
217+
/// [`lsps5.list_webhooks`]: super::msgs::LSPS5Request::ListWebhooks
218+
WebhooksListFailed {
219+
/// The node id of the LSP that rejected the request.
220+
counterparty_node_id: PublicKey,
221+
/// Error from the LSP.
222+
error: LSPS5Error,
223+
/// The identifier of the issued bLIP-55 / LSPS5 list webhooks request.
224+
///
225+
/// This can be used to track which request this event corresponds to.
226+
request_id: LSPSRequestId,
227+
},
228+
229+
/// A webhook was successfully removed.
230+
///
231+
/// This event is triggered when the LSP confirms successful removal
232+
/// of a webhook via [`lsps5.remove_webhook`]. The webhook registration
233+
/// has been deleted from the LSP's system and will no longer receive
234+
/// notifications.
235+
///
236+
/// When this event occurs, the client should:
237+
/// 1. Update any UI to reflect the webhook removal
238+
/// 2. Remove the webhook from any local storage or cache
239+
/// 3. Update counters or indicators showing the number of registered webhooks
240+
/// 4. Take any application-specific cleanup actions for the removed webhook
241+
///
242+
/// After this event, the app_name is free to be reused for a new webhook
243+
/// registration if desired.
244+
///
245+
/// [`lsps5.remove_webhook`]: super::msgs::LSPS5Request::RemoveWebhook
246+
WebhookRemoved {
247+
/// The node id of the LSP that confirmed the removal.
248+
counterparty_node_id: PublicKey,
249+
/// The app name that was removed.
250+
app_name: LSPS5AppName,
251+
/// The identifier of the issued bLIP-55 / LSPS5 remove webhook request.
252+
///
253+
/// This can be used to track which request this event corresponds to.
254+
request_id: LSPSRequestId,
255+
},
256+
257+
/// A webhook removal attempt failed.
258+
///
259+
/// This event is triggered when the LSP rejects a webhook removal
260+
/// via [`lsps5.remove_webhook`]. The most common scenario is attempting
261+
/// to remove a webhook that doesn't exist or was already removed.
262+
///
263+
/// When this event occurs, the client should:
264+
/// 1. Present an appropriate error message to the user
265+
/// 2. If the error is [`AppNameNotFound`], update any local state to
266+
/// reflect that the webhook does not exist on the server
267+
/// 3. Consider refreshing the webhook list to ensure local state
268+
/// matches server state
269+
///
270+
/// The most common error is [`LSPS5ProtocolError::AppNameNotFound`]
271+
/// (error code [`LSPS5_APP_NAME_NOT_FOUND_ERROR_CODE`]), which indicates
272+
/// the given [`app_name`] was not found in the LSP's registration database.
273+
///
274+
/// [`lsps5.remove_webhook`]: super::msgs::LSPS5Request::RemoveWebhook
275+
/// [`AppNameNotFound`]: super::msgs::LSPS5ProtocolError::AppNameNotFound
276+
/// [`LSPS5ProtocolError::AppNameNotFound`]: super::msgs::LSPS5ProtocolError::AppNameNotFound
277+
/// [`LSPS5_APP_NAME_NOT_FOUND_ERROR_CODE`]: super::msgs::LSPS5_APP_NAME_NOT_FOUND_ERROR_CODE
278+
/// [`app_name`]: super::msgs::LSPS5AppName
279+
WebhookRemovalFailed {
280+
/// The node id of the LSP that rejected the removal.
281+
counterparty_node_id: PublicKey,
282+
/// Error from the LSP.
283+
error: LSPS5Error,
284+
/// The app name that was attempted to be removed.
285+
app_name: LSPS5AppName,
286+
/// The identifier of the issued bLIP-55 / LSPS5 remove webhook request.
287+
///
288+
/// This can be used to track which request this event corresponds to.
289+
request_id: LSPSRequestId,
290+
},
291+
292+
/// A webhook notification was received from the LSP.
293+
///
294+
/// This event is triggered when the client receives and successfully
295+
/// verifies a webhook notification from the LSP. This represents an
296+
/// asynchronous event that the LSP is notifying the client about.
297+
///
298+
/// When this event occurs, the client should:
299+
/// 1. Check `signature_valid` to confirm the notification is authentic
300+
/// 2. Examine the `notification.method` to determine the type of notification
301+
/// 3. Process the notification according to its method and parameters
302+
/// 4. Update any UI or take actions based on the notification type
303+
///
304+
/// Common notification methods include:
305+
/// - [`LSPS5WebhookRegistered`] - Initial test notification after registration
306+
/// - [`LSPS5PaymentIncoming`] - Client has pending incoming payments
307+
/// - [`LSPS5ExpirySoon`] - An HTLC or contract will expire soon
308+
/// - [`LSPS5LiquidityManagementRequest`] - LSP needs to manage liquidity
309+
/// - [`LSPS5OnionMessageIncoming`] - Client has pending onion messages
310+
///
311+
/// The client should reject notifications with invalid signatures or timestamps
312+
/// more than 10 minutes from the current time.
313+
///
314+
/// [`LSPS5WebhookRegistered`]: super::msgs::WebhookNotificationMethod::LSPS5WebhookRegistered
315+
/// [`LSPS5PaymentIncoming`]: super::msgs::WebhookNotificationMethod::LSPS5PaymentIncoming
316+
/// [`LSPS5ExpirySoon`]: super::msgs::WebhookNotificationMethod::LSPS5ExpirySoon
317+
/// [`LSPS5LiquidityManagementRequest`]: super::msgs::WebhookNotificationMethod::LSPS5LiquidityManagementRequest
318+
/// [`LSPS5OnionMessageIncoming`]: super::msgs::WebhookNotificationMethod::LSPS5OnionMessageIncoming
319+
WebhookNotificationReceived {
320+
/// LSP node ID that sent the notification.
321+
counterparty_node_id: PublicKey,
322+
/// The notification with its method and parameters.
323+
notification: WebhookNotification,
324+
/// Timestamp of the notification.
325+
timestamp: LSPSDateTime,
326+
/// Whether the LSP's signature was successfully verified.
327+
signature_valid: bool,
328+
},
329+
}

0 commit comments

Comments
 (0)