Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/api-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ See [Pagination](#pagination) below for how to page through results.
| `PaymentClaimable` | A hodl invoice payment arrived and is waiting to be claimed or failed |
| `PaymentForwarded` | A payment was routed through this node |
| `ChannelStateChanged` | A channel changed state (pending, ready, open failed, closed) |
| `SpliceNegotiated` | A channel splice was negotiated and the funding transaction is pending confirmation |
| `SpliceNegotiationFailed` | A channel splice negotiation round failed |

Events are broadcast to all connected subscribers. The server uses a bounded broadcast channel
(capacity 1024). A slow subscriber that falls behind will miss events.
Expand Down
13 changes: 13 additions & 0 deletions e2e-tests/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,11 +1200,24 @@ async fn splice_in_via_cli(splice_amount: &str) {
let server_b = LdkServerHandle::start(&bitcoind).await;
let user_channel_id = setup_funded_channel(&bitcoind, &server_a, &server_b, 100_000).await;

let mut events_a = server_a.client().subscribe_events().await.unwrap();

let output = run_cli(
&server_a,
&["splice-in", &user_channel_id, server_b.node_id(), splice_amount],
);
assert!(output.is_object());

let event_a =
wait_for_event(&mut events_a, |e| matches!(e, Event::SpliceNegotiated(_))).await;
match &event_a.event {
Some(Event::SpliceNegotiated(splice_negotiated)) => {
assert_eq!(splice_negotiated.user_channel_id, user_channel_id);
assert_eq!(splice_negotiated.counterparty_node_id, server_b.node_id());
assert!(!splice_negotiated.new_funding_txo.is_empty());
},
other => panic!("expected SpliceNegotiated event, got {other:?}"),
}
}

#[tokio::test]
Expand Down
38 changes: 37 additions & 1 deletion ldk-server-grpc/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EventEnvelope {
#[prost(oneof = "event_envelope::Event", tags = "2, 3, 4, 6, 7, 8")]
#[prost(oneof = "event_envelope::Event", tags = "2, 3, 4, 6, 7, 8, 9, 10")]
pub event: ::core::option::Option<event_envelope::Event>,
}
/// Nested message and enum types in `EventEnvelope`.
Expand All @@ -36,6 +36,10 @@ pub mod event_envelope {
PaymentClaimable(super::PaymentClaimable),
#[prost(message, tag = "8")]
ChannelStateChanged(super::ChannelStateChanged),
#[prost(message, tag = "9")]
SpliceNegotiated(super::SpliceNegotiated),
#[prost(message, tag = "10")]
SpliceNegotiationFailed(super::SpliceNegotiationFailed),
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -140,6 +144,38 @@ pub struct ChannelStateChanged {
#[prost(enumeration = "ChannelClosureInitiator", tag = "7")]
pub closure_initiator: i32,
}
/// SpliceNegotiated indicates a channel splice has been negotiated and the funding
/// transaction is pending confirmation on-chain.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "serde", serde(default))]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SpliceNegotiated {
#[prost(string, tag = "1")]
pub channel_id: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub user_channel_id: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub counterparty_node_id: ::prost::alloc::string::String,
/// The outpoint of the channel's splice funding transaction.
#[prost(string, tag = "4")]
pub new_funding_txo: ::prost::alloc::string::String,
}
/// SpliceNegotiationFailed indicates a channel splice negotiation round has failed.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
#[cfg_attr(feature = "serde", serde(default))]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SpliceNegotiationFailed {
#[prost(string, tag = "1")]
pub channel_id: ::prost::alloc::string::String,
#[prost(string, tag = "2")]
pub user_channel_id: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub counterparty_node_id: ::prost::alloc::string::String,
}
/// PaymentReceived indicates a payment has been received.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
Expand Down
19 changes: 19 additions & 0 deletions ldk-server-grpc/src/proto/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ message EventEnvelope {
PaymentForwarded payment_forwarded = 6;
PaymentClaimable payment_claimable = 7;
ChannelStateChanged channel_state_changed = 8;
SpliceNegotiated splice_negotiated = 9;
SpliceNegotiationFailed splice_negotiation_failed = 10;
}
}

Expand Down Expand Up @@ -120,6 +122,23 @@ message ChannelStateChanged {
ChannelClosureInitiator closure_initiator = 7;
}

// SpliceNegotiated indicates a channel splice has been negotiated and the funding
// transaction is pending confirmation on-chain.
message SpliceNegotiated {
string channel_id = 1;
string user_channel_id = 2;
string counterparty_node_id = 3;
// The outpoint of the channel's splice funding transaction.
string new_funding_txo = 4;
}

// SpliceNegotiationFailed indicates a channel splice negotiation round has failed.
message SpliceNegotiationFailed {
string channel_id = 1;
string user_channel_id = 2;
string counterparty_node_id = 3;
}

// PaymentReceived indicates a payment has been received.
message PaymentReceived {
// The payment details for the payment in event.
Expand Down
48 changes: 47 additions & 1 deletion ldk-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,57 @@ fn main() {
}
}
},
_ => {
Event::SpliceNegotiated {
channel_id,
user_channel_id,
counterparty_node_id,
new_funding_txo,
} => {
info!(
"SPLICE_NEGOTIATED: {} from counterparty {}",
channel_id, counterparty_node_id
);

send_channel_state_event(
event_envelope::Event::SpliceNegotiated(events::SpliceNegotiated {
channel_id: channel_id.0.to_lower_hex_string(),
user_channel_id: user_channel_id.0.to_string(),
counterparty_node_id: counterparty_node_id.to_string(),
new_funding_txo: new_funding_txo.to_string(),
}),
&event_sender,
);

if let Err(e) = event_node.event_handled() {
error!("Failed to mark event as handled: {e}");
}
},
Event::SpliceNegotiationFailed {
channel_id,
user_channel_id,
counterparty_node_id,
} => {
info!(
"SPLICE_NEGOTIATION_FAILED: {} from counterparty {}",
channel_id, counterparty_node_id
);

send_channel_state_event(
event_envelope::Event::SpliceNegotiationFailed(
events::SpliceNegotiationFailed {
channel_id: channel_id.0.to_lower_hex_string(),
user_channel_id: user_channel_id.0.to_string(),
counterparty_node_id: counterparty_node_id.to_string(),
},
),
&event_sender,
);

if let Err(e) = event_node.event_handled() {
error!("Failed to mark event as handled: {e}");
}
},

}
},
res = grpc_listener.accept() => {
Expand Down