use core::time::Duration;
use core::ops::Deref;
+/// Some information provided on receipt of payment depends on whether the payment received is a
+/// spontaneous payment or a "conventional" lightning payment that's paying an invoice.
+#[derive(Clone, Debug)]
+pub enum PaymentPurpose {
+ /// Information for receiving a payment that we generated an invoice for.
+ InvoicePayment {
+ /// The preimage to the payment_hash, if the payment hash (and secret) were fetched via
+ /// [`ChannelManager::create_inbound_payment`]. If provided, this can be handed directly to
+ /// [`ChannelManager::claim_funds`].
+ ///
+ /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
+ /// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds
+ payment_preimage: Option<PaymentPreimage>,
+ /// The "payment secret". This authenticates the sender to the recipient, preventing a
+ /// number of deanonymization attacks during the routing process.
+ /// It is provided here for your reference, however its accuracy is enforced directly by
+ /// [`ChannelManager`] using the values you previously provided to
+ /// [`ChannelManager::create_inbound_payment`] or
+ /// [`ChannelManager::create_inbound_payment_for_hash`].
+ ///
+ /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
+ /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
+ /// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
+ payment_secret: PaymentSecret,
+ /// This is the `user_payment_id` which was provided to
+ /// [`ChannelManager::create_inbound_payment_for_hash`] or
+ /// [`ChannelManager::create_inbound_payment`]. It has no meaning inside of LDK and is
+ /// simply copied here. It may be used to correlate PaymentReceived events with invoice
+ /// metadata stored elsewhere.
+ ///
+ /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
+ /// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
+ user_payment_id: u64,
+ },
+ /// Because this is a spontaneous payment, the payer generated their own preimage rather than us
+ /// (the payee) providing a preimage.
+ SpontaneousPayment(PaymentPreimage),
+}
+
/// An Event which you should probably take some action in response to.
///
/// Note that while Writeable and Readable are implemented for Event, you probably shouldn't use
PaymentReceived {
/// The hash for which the preimage should be handed to the ChannelManager.
payment_hash: PaymentHash,
- /// The preimage to the payment_hash, if the payment hash (and secret) were fetched via
- /// [`ChannelManager::create_inbound_payment`]. If provided, this can be handed directly to
- /// [`ChannelManager::claim_funds`].
- ///
- /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
- /// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds
- payment_preimage: Option<PaymentPreimage>,
- /// The "payment secret". This authenticates the sender to the recipient, preventing a
- /// number of deanonymization attacks during the routing process.
- /// It is provided here for your reference, however its accuracy is enforced directly by
- /// [`ChannelManager`] using the values you previously provided to
- /// [`ChannelManager::create_inbound_payment`] or
- /// [`ChannelManager::create_inbound_payment_for_hash`].
- ///
- /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager
- /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
- /// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
- payment_secret: PaymentSecret,
/// The value, in thousandths of a satoshi, that this payment is for. Note that you must
/// compare this to the expected value before accepting the payment (as otherwise you are
/// providing proof-of-payment for less than the value you expected!).
amt: u64,
- /// This is the `user_payment_id` which was provided to
- /// [`ChannelManager::create_inbound_payment_for_hash`] or
- /// [`ChannelManager::create_inbound_payment`]. It has no meaning inside of LDK and is
- /// simply copied here. It may be used to correlate PaymentReceived events with invoice
- /// metadata stored elsewhere.
- ///
- /// [`ChannelManager::create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment
- /// [`ChannelManager::create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash
- user_payment_id: u64,
+ /// Information for claiming this received payment, based on whether the purpose of the
+ /// payment is to pay an invoice or to send a spontaneous payment.
+ purpose: PaymentPurpose,
},
/// Indicates an outbound payment we made succeeded (ie it made it all the way to its target
/// and we got back the payment preimage for it).
/// now + 5*time_forwardable).
time_forwardable: Duration,
},
- /// Used to indicate that an output was generated on-chain which you should know how to spend.
+ /// Used to indicate that an output which you should know how to spend was confirmed on chain
+ /// and is now spendable.
/// Such an output will *not* ever be spent by rust-lightning, and are not at risk of your
/// counterparty spending them due to some kind of timeout. Thus, you need to store them
/// somewhere and spend them when you create on-chain transactions.
/// The outputs which you should store as spendable by you.
outputs: Vec<SpendableOutputDescriptor>,
},
+ /// This event is generated when a payment has been successfully forwarded through us and a
+ /// forwarding fee earned.
+ PaymentForwarded {
+ /// The 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`. It is possible duplicate
+ /// `PaymentForwarded` events are generated for the same payment iff `fee_earned_msat` is
+ /// `None`.
+ fee_earned_msat: Option<u64>,
+ /// If this is `true`, the forwarded HTLC was claimed by our counterparty via an on-chain
+ /// transaction.
+ claim_from_onchain_tx: bool,
+ },
}
impl Writeable for Event {
// We never write out FundingGenerationReady events as, upon disconnection, peers
// drop any channels which have not yet exchanged funding_signed.
},
- &Event::PaymentReceived { ref payment_hash, ref payment_preimage, ref payment_secret, ref amt, ref user_payment_id } => {
+ &Event::PaymentReceived { ref payment_hash, ref amt, ref purpose } => {
1u8.write(writer)?;
+ let mut payment_secret = None;
+ let mut user_payment_id = None;
+ let payment_preimage;
+ match &purpose {
+ PaymentPurpose::InvoicePayment { payment_preimage: preimage, payment_secret: secret, user_payment_id: id } => {
+ payment_secret = Some(secret);
+ payment_preimage = *preimage;
+ user_payment_id = Some(id);
+ },
+ PaymentPurpose::SpontaneousPayment(preimage) => {
+ payment_preimage = Some(*preimage);
+ }
+ }
write_tlv_fields!(writer, {
- (0, payment_hash),
- (2, payment_secret),
- (4, amt),
- (6, user_payment_id),
- }, {
- (8, payment_preimage),
+ (0, payment_hash, required),
+ (2, payment_secret, option),
+ (4, amt, required),
+ (6, user_payment_id, option),
+ (8, payment_preimage, option),
});
},
&Event::PaymentSent { ref payment_preimage } => {
2u8.write(writer)?;
write_tlv_fields!(writer, {
- (0, payment_preimage),
- }, {});
- payment_preimage.write(writer)?;
+ (0, payment_preimage, required),
+ });
},
&Event::PaymentFailed { ref payment_hash, ref rejected_by_dest,
#[cfg(test)]
#[cfg(test)]
error_data.write(writer)?;
write_tlv_fields!(writer, {
- (0, payment_hash),
- (2, rejected_by_dest),
- }, {});
+ (0, payment_hash, required),
+ (2, rejected_by_dest, required),
+ });
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
4u8.write(writer)?;
- write_tlv_fields!(writer, {}, {});
+ write_tlv_fields!(writer, {});
// We don't write the time_fordwardable out at all, as we presume when the user
// deserializes us at least that much time has elapsed.
},
&Event::SpendableOutputs { ref outputs } => {
5u8.write(writer)?;
write_tlv_fields!(writer, {
- (0, VecWriteWrapper(outputs)),
- }, {});
+ (0, VecWriteWrapper(outputs), required),
+ });
+ },
+ &Event::PaymentForwarded { fee_earned_msat, claim_from_onchain_tx } => {
+ 7u8.write(writer)?;
+ write_tlv_fields!(writer, {
+ (0, fee_earned_msat, option),
+ (2, claim_from_onchain_tx, required),
+ });
},
}
Ok(())
let f = || {
let mut payment_hash = PaymentHash([0; 32]);
let mut payment_preimage = None;
- let mut payment_secret = PaymentSecret([0; 32]);
+ let mut payment_secret = None;
let mut amt = 0;
- let mut user_payment_id = 0;
+ let mut user_payment_id = None;
read_tlv_fields!(reader, {
- (0, payment_hash),
- (2, payment_secret),
- (4, amt),
- (6, user_payment_id),
- }, {
- (8, payment_preimage),
+ (0, payment_hash, required),
+ (2, payment_secret, option),
+ (4, amt, required),
+ (6, user_payment_id, option),
+ (8, payment_preimage, option),
});
+ let purpose = match payment_secret {
+ Some(secret) => PaymentPurpose::InvoicePayment {
+ payment_preimage,
+ payment_secret: secret,
+ user_payment_id: if let Some(id) = user_payment_id {
+ id
+ } else { return Err(msgs::DecodeError::InvalidValue) }
+ },
+ None if payment_preimage.is_some() => PaymentPurpose::SpontaneousPayment(payment_preimage.unwrap()),
+ None => return Err(msgs::DecodeError::InvalidValue),
+ };
Ok(Some(Event::PaymentReceived {
payment_hash,
- payment_preimage,
- payment_secret,
amt,
- user_payment_id,
+ purpose,
}))
};
f()
let f = || {
let mut payment_preimage = PaymentPreimage([0; 32]);
read_tlv_fields!(reader, {
- (0, payment_preimage),
- }, {});
+ (0, payment_preimage, required),
+ });
Ok(Some(Event::PaymentSent {
payment_preimage,
}))
let mut payment_hash = PaymentHash([0; 32]);
let mut rejected_by_dest = false;
read_tlv_fields!(reader, {
- (0, payment_hash),
- (2, rejected_by_dest),
- }, {});
+ (0, payment_hash, required),
+ (2, rejected_by_dest, required),
+ });
Ok(Some(Event::PaymentFailed {
payment_hash,
rejected_by_dest,
},
4u8 => {
let f = || {
- read_tlv_fields!(reader, {}, {});
+ read_tlv_fields!(reader, {});
Ok(Some(Event::PendingHTLCsForwardable {
time_forwardable: Duration::from_secs(0)
}))
let f = || {
let mut outputs = VecReadWrapper(Vec::new());
read_tlv_fields!(reader, {
- (0, outputs),
- }, {});
+ (0, outputs, required),
+ });
Ok(Some(Event::SpendableOutputs { outputs: outputs.0 }))
};
f()
},
+ 7u8 => {
+ let f = || {
+ let mut fee_earned_msat = None;
+ let mut claim_from_onchain_tx = false;
+ read_tlv_fields!(reader, {
+ (0, fee_earned_msat, option),
+ (2, claim_from_onchain_tx, required),
+ });
+ Ok(Some(Event::PaymentForwarded { fee_earned_msat, claim_from_onchain_tx }))
+ };
+ f()
+ },
+ // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue.
+ x if x % 2 == 1 => Ok(None),
_ => Err(msgs::DecodeError::InvalidValue)
}
}
/// The channel_update which should be sent.
msg: msgs::ChannelUpdate,
},
+ /// Used to indicate that a channel_update should be sent to a single peer.
+ /// In contrast to [`Self::BroadcastChannelUpdate`], this is used when the channel is a
+ /// private channel and we shouldn't be informing all of our peers of channel parameters.
+ SendChannelUpdate {
+ /// The node_id of the node which should receive this message
+ node_id: PublicKey,
+ /// The channel_update which should be sent.
+ msg: msgs::ChannelUpdate,
+ },
/// Broadcast an error downstream to be handled
HandleError {
/// The node_id of the node which should receive this message