From d8d900205c1aadcb3a007052fd0c9ca481678589 Mon Sep 17 00:00:00 2001 From: G8XSU <3442979+G8XSU@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:27:44 -0800 Subject: [PATCH] Start publishing PaymentForwarded events. Required for ldk-server implementation or rather any forwarding node. Since a mobile node shouldn't be forwarding payments, these shouldn't get generated for mobile nodes. --- bindings/ldk_node.udl | 1 + src/event.rs | 73 ++++++++++++++++++++++++++++++++- tests/integration_tests_rust.rs | 3 ++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 8238ba4c4..954a6403c 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -277,6 +277,7 @@ interface Event { PaymentFailed(PaymentId? payment_id, PaymentHash? payment_hash, PaymentFailureReason? reason); PaymentReceived(PaymentId? payment_id, PaymentHash payment_hash, u64 amount_msat); PaymentClaimable(PaymentId payment_id, PaymentHash payment_hash, u64 claimable_amount_msat, u32? claim_deadline); + PaymentForwarded(ChannelId prev_channel_id, ChannelId next_channel_id, UserChannelId? prev_user_channel_id, UserChannelId? next_user_channel_id, u64? total_fee_earned_msat, u64? skimmed_fee_msat, boolean claim_from_onchain_tx, u64? outbound_amount_forwarded_msat); ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo); ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id); ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason); diff --git a/src/event.rs b/src/event.rs index 6ba6d2145..d760d3b58 100644 --- a/src/event.rs +++ b/src/event.rs @@ -103,6 +103,50 @@ pub enum Event { /// The value, in thousandths of a satoshi, that has been received. amount_msat: u64, }, + /// A payment has been forwarded. + PaymentForwarded { + /// The channel id of the incoming channel between the previous node and us. + prev_channel_id: ChannelId, + /// The channel id of the outgoing channel between the next node and us. + next_channel_id: ChannelId, + /// The `user_channel_id` of the incoming channel between the previous node and us. + /// + /// Will only be `None` for events serialized with LDK Node v0.3.0 or prior. + prev_user_channel_id: Option, + /// The `user_channel_id` of the outgoing channel between the next node and us. + /// + /// This will be `None` if the payment was settled via an on-chain transaction. See the + /// caveat described for the `total_fee_earned_msat` field. + next_user_channel_id: Option, + /// The total fee, in milli-satoshis, which was earned as a result of the payment. + /// + /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC + /// was pending, the amount the next hop claimed will have been rounded down to the nearest + /// whole satoshi. Thus, the fee calculated here may be higher than expected as we still + /// claimed the full value in millisatoshis from the source. In this case, + /// `claim_from_onchain_tx` will be set. + /// + /// If the channel which sent us the payment has been force-closed, we will claim the funds + /// via an on-chain transaction. In that case we do not yet know the on-chain transaction + /// fees which we will spend and will instead set this to `None`. + total_fee_earned_msat: Option, + /// The share of the total fee, in milli-satoshis, which was withheld in addition to the + /// forwarding fee. + /// + /// This will only be `Some` if we forwarded an intercepted HTLC with less than the + /// expected amount. This means our counterparty accepted to receive less than the invoice + /// amount. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + skimmed_fee_msat: Option, + /// If this is `true`, the forwarded HTLC was claimed by our counterparty via an on-chain + /// transaction. + claim_from_onchain_tx: bool, + /// The final amount forwarded, in milli-satoshis, after the fee is deducted. + /// + /// The caveat described above the `total_fee_earned_msat` field applies here as well. + outbound_amount_forwarded_msat: Option, + }, /// A payment for a previously-registered payment hash has been received. /// /// This needs to be manually claimed by supplying the correct preimage to [`claim_for_hash`]. @@ -204,6 +248,16 @@ impl_writeable_tlv_based_enum!(Event, (2, payment_id, required), (4, claimable_amount_msat, required), (6, claim_deadline, option), + }, + (7, PaymentForwarded) => { + (0, prev_channel_id, required), + (2, next_channel_id, required), + (4, prev_user_channel_id, option), + (6, next_user_channel_id, option), + (8, total_fee_earned_msat, option), + (10, skimmed_fee_msat, option), + (12, claim_from_onchain_tx, required), + (14, outbound_amount_forwarded_msat, option), } ); @@ -1068,11 +1122,28 @@ where LdkEvent::PaymentForwarded { prev_channel_id, next_channel_id, + prev_user_channel_id, + next_user_channel_id, total_fee_earned_msat, + skimmed_fee_msat, claim_from_onchain_tx, outbound_amount_forwarded_msat, - .. } => { + let event = Event::PaymentForwarded { + prev_channel_id: prev_channel_id.expect("prev_channel_id expected for events generated by LDK versions greater than 0.0.107."), + next_channel_id: next_channel_id.expect("next_channel_id expected for events generated by LDK versions greater than 0.0.107."), + prev_user_channel_id: prev_user_channel_id.map(UserChannelId), + next_user_channel_id: next_user_channel_id.map(UserChannelId), + total_fee_earned_msat, + skimmed_fee_msat, + claim_from_onchain_tx, + outbound_amount_forwarded_msat, + }; + self.event_queue.add_event(event).map_err(|e| { + log_error!(self.logger, "Failed to push to event queue: {}", e); + ReplayEvent() + })?; + let read_only_network_graph = self.network_graph.read_only(); let nodes = read_only_network_graph.nodes(); let channels = self.channel_manager.list_channels(); diff --git a/tests/integration_tests_rust.rs b/tests/integration_tests_rust.rs index 31990440e..937af241b 100644 --- a/tests/integration_tests_rust.rs +++ b/tests/integration_tests_rust.rs @@ -192,6 +192,9 @@ fn multi_hop_sending() { let invoice = nodes[4].bolt11_payment().receive(2_500_000, &"asdf", 9217).unwrap(); nodes[0].bolt11_payment().send(&invoice, Some(sending_params)).unwrap(); + expect_event!(nodes[1], PaymentForwarded); + expect_event!(nodes[2], PaymentForwarded); + let payment_id = expect_payment_received_event!(&nodes[4], 2_500_000); let fee_paid_msat = Some(2000); expect_payment_successful_event!(nodes[0], payment_id, Some(fee_paid_msat));