//! few other things.
use chain::keysinterface::SpendableOutputDescriptor;
+use ln::channelmanager::PaymentId;
+use ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
use ln::msgs;
use ln::msgs::DecodeError;
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
use routing::network_graph::NetworkUpdate;
use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper};
-use routing::router::RouteHop;
+use routing::router::{RouteHop, RouteParameters};
+use bitcoin::Transaction;
use bitcoin::blockdata::script::Script;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
use prelude::*;
use core::time::Duration;
use core::ops::Deref;
-use bitcoin::Transaction;
+use sync::Arc;
/// 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.
/// [`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.
/// commitment transaction came from our counterparty, but it may also have come from
/// a copy of our own `ChannelMonitor`.
CommitmentTxConfirmed,
+ /// The funding transaction failed to confirm in a timely manner on an inbound channel.
+ FundingTimedOut,
/// Closure generated from processing an event, likely a HTLC forward/relay/reception.
ProcessingError {
/// A developer-readable error message which we generated.
OutdatedChannelManager
}
+impl core::fmt::Display for ClosureReason {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
+ f.write_str("Channel closed because ")?;
+ match self {
+ ClosureReason::CounterpartyForceClosed { peer_msg } => {
+ f.write_str("counterparty force-closed with message ")?;
+ f.write_str(&peer_msg)
+ },
+ ClosureReason::HolderForceClosed => f.write_str("user manually force-closed the channel"),
+ ClosureReason::CooperativeClosure => f.write_str("the channel was cooperatively closed"),
+ ClosureReason::CommitmentTxConfirmed => f.write_str("commitment or closing transaction was confirmed on chain."),
+ ClosureReason::FundingTimedOut => write!(f, "funding transaction failed to confirm within {} blocks", FUNDING_CONF_DEADLINE_BLOCKS),
+ ClosureReason::ProcessingError { err } => {
+ f.write_str("of an exception: ")?;
+ f.write_str(&err)
+ },
+ ClosureReason::DisconnectedPeer => f.write_str("the peer disconnected prior to the channel being funded"),
+ ClosureReason::OutdatedChannelManager => f.write_str("the ChannelManager read from disk was stale compared to ChannelMonitor(s)"),
+ }
+ }
+}
+
impl_writeable_tlv_based_enum_upgradable!(ClosureReason,
(0, CounterpartyForceClosed) => { (1, peer_msg, required) },
+ (1, FundingTimedOut) => {},
(2, HolderForceClosed) => {},
(6, CommitmentTxConfirmed) => {},
(4, CooperativeClosure) => {},
/// Note for MPP payments: in rare cases, this event may be preceded by a `PaymentPathFailed`
/// event. In this situation, you SHOULD treat this payment as having succeeded.
PaymentSent {
+ /// The id returned by [`ChannelManager::send_payment`] and used with
+ /// [`ChannelManager::retry_payment`].
+ ///
+ /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
+ /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
+ payment_id: Option<PaymentId>,
/// The preimage to the hash given to ChannelManager::send_payment.
/// Note that this serves as a payment receipt, if you wish to have such a thing, you must
/// store it somehow!
///
/// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
payment_hash: PaymentHash,
+ /// The total fee which was spent at intermediate hops in this payment, across all paths.
+ ///
+ /// Note that, like [`Route::get_total_fees`] this does *not* include any potential
+ /// overpayment to the recipient node.
+ ///
+ /// If the recipient or an intermediate node misbehaves and gives us free money, this may
+ /// overstate the amount paid, though this is unlikely.
+ ///
+ /// [`Route::get_total_fees`]: crate::routing::router::Route::get_total_fees
+ fee_paid_msat: Option<u64>,
},
/// Indicates an outbound payment we made failed. Probably some intermediary node dropped
/// something. You may wish to retry with a different route.
PaymentPathFailed {
+ /// The id returned by [`ChannelManager::send_payment`] and used with
+ /// [`ChannelManager::retry_payment`].
+ ///
+ /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment
+ /// [`ChannelManager::retry_payment`]: crate::ln::channelmanager::ChannelManager::retry_payment
+ payment_id: Option<PaymentId>,
/// The hash which was given to ChannelManager::send_payment.
payment_hash: PaymentHash,
/// Indicates the payment was rejected for some reason by the recipient. This implies that
/// If this is `Some`, then the corresponding channel should be avoided when the payment is
/// retried. May be `None` for older [`Event`] serializations.
short_channel_id: Option<u64>,
+ /// Parameters needed to compute a new [`Route`] when retrying the failed payment path.
+ ///
+ /// See [`find_route`] for details.
+ ///
+ /// [`Route`]: crate::routing::router::Route
+ /// [`find_route`]: crate::routing::router::find_route
+ retry: Option<RouteParameters>,
#[cfg(test)]
error_code: Option<u16>,
#[cfg(test)]
&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 } => {
+ PaymentPurpose::InvoicePayment { payment_preimage: preimage, payment_secret: secret } => {
payment_secret = Some(secret);
payment_preimage = *preimage;
- user_payment_id = Some(id);
},
PaymentPurpose::SpontaneousPayment(preimage) => {
payment_preimage = Some(*preimage);
(0, payment_hash, required),
(2, payment_secret, option),
(4, amt, required),
- (6, user_payment_id, option),
+ (6, 0u64, required), // user_payment_id required for compatibility with 0.0.103 and earlier
(8, payment_preimage, option),
});
},
- &Event::PaymentSent { ref payment_preimage, ref payment_hash} => {
+ &Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
2u8.write(writer)?;
write_tlv_fields!(writer, {
(0, payment_preimage, required),
(1, payment_hash, required),
+ (3, payment_id, option),
+ (5, fee_paid_msat, option),
});
},
- &Event::PaymentPathFailed { ref payment_hash, ref rejected_by_dest, ref network_update,
- ref all_paths_failed, ref path, ref short_channel_id,
+ &Event::PaymentPathFailed {
+ ref payment_id, ref payment_hash, ref rejected_by_dest, ref network_update,
+ ref all_paths_failed, ref path, ref short_channel_id, ref retry,
#[cfg(test)]
ref error_code,
#[cfg(test)]
(3, all_paths_failed, required),
(5, path, vec_type),
(7, short_channel_id, option),
+ (9, retry, option),
+ (11, payment_id, option),
});
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
let mut payment_preimage = None;
let mut payment_secret = None;
let mut amt = 0;
- let mut user_payment_id = None;
+ let mut _user_payment_id = None; // For compatibility with 0.0.103 and earlier
read_tlv_fields!(reader, {
(0, payment_hash, required),
(2, payment_secret, option),
(4, amt, required),
- (6, user_payment_id, option),
+ (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) }
+ payment_secret: secret
},
None if payment_preimage.is_some() => PaymentPurpose::SpontaneousPayment(payment_preimage.unwrap()),
None => return Err(msgs::DecodeError::InvalidValue),
let f = || {
let mut payment_preimage = PaymentPreimage([0; 32]);
let mut payment_hash = None;
+ let mut payment_id = None;
+ let mut fee_paid_msat = None;
read_tlv_fields!(reader, {
(0, payment_preimage, required),
(1, payment_hash, option),
+ (3, payment_id, option),
+ (5, fee_paid_msat, option),
});
if payment_hash.is_none() {
payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()));
}
Ok(Some(Event::PaymentSent {
+ payment_id,
payment_preimage,
payment_hash: payment_hash.unwrap(),
+ fee_paid_msat,
}))
};
f()
let mut all_paths_failed = Some(true);
let mut path: Option<Vec<RouteHop>> = Some(vec![]);
let mut short_channel_id = None;
+ let mut retry = None;
+ let mut payment_id = None;
read_tlv_fields!(reader, {
(0, payment_hash, required),
(1, network_update, ignorable),
(2, rejected_by_dest, required),
(3, all_paths_failed, option),
(5, path, vec_type),
- (7, short_channel_id, ignorable),
+ (7, short_channel_id, option),
+ (9, retry, option),
+ (11, payment_id, option),
});
Ok(Some(Event::PaymentPathFailed {
+ payment_id,
payment_hash,
rejected_by_dest,
network_update,
all_paths_failed: all_paths_failed.unwrap(),
path: path.unwrap(),
short_channel_id,
+ retry,
#[cfg(test)]
error_code,
#[cfg(test)]
self(event)
}
}
+
+impl<T: EventHandler> EventHandler for Arc<T> {
+ fn handle_event(&self, event: &Event) {
+ self.deref().handle_event(event)
+ }
+}