X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fevents.rs;h=e9f456cfe69750743fc21b787272ddf41814ee87;hb=2d102a3065d7a438d5c88fffcad36545a0822bfa;hp=df4d9037307c30cb20e32c9b36a07ff6c10cd4b5;hpb=8f78bbda8921af9a8094adc74c84e24fda5099f8;p=rust-lightning diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index df4d9037..e9f456cf 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -15,19 +15,24 @@ //! few other things. use chain::keysinterface::SpendableOutputDescriptor; +use ln::channelmanager::PaymentId; use ln::msgs; +use ln::msgs::DecodeError; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use routing::network_graph::NetworkUpdate; -use util::ser::{Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper}; +use util::ser::{BigSize, FixedLengthReader, Writeable, Writer, MaybeReadable, Readable, VecReadWrapper, VecWriteWrapper}; +use routing::router::{RouteHop, RouteParameters}; use bitcoin::blockdata::script::Script; - +use bitcoin::hashes::Hash; +use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::key::PublicKey; use io; use prelude::*; use core::time::Duration; use core::ops::Deref; +use bitcoin::Transaction; /// 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. @@ -68,6 +73,60 @@ pub enum PaymentPurpose { SpontaneousPayment(PaymentPreimage), } +#[derive(Clone, Debug, PartialEq)] +/// The reason the channel was closed. See individual variants more details. +pub enum ClosureReason { + /// Closure generated from receiving a peer error message. + /// + /// Our counterparty may have broadcasted their latest commitment state, and we have + /// as well. + CounterpartyForceClosed { + /// The error which the peer sent us. + /// + /// The string should be sanitized before it is used (e.g emitted to logs + /// or printed to stdout). Otherwise, a well crafted error message may exploit + /// a security vulnerability in the terminal emulator or the logging subsystem. + peer_msg: String, + }, + /// Closure generated from [`ChannelManager::force_close_channel`], called by the user. + /// + /// [`ChannelManager::force_close_channel`]: crate::ln::channelmanager::ChannelManager::force_close_channel. + HolderForceClosed, + /// The channel was closed after negotiating a cooperative close and we've now broadcasted + /// the cooperative close transaction. Note the shutdown may have been initiated by us. + //TODO: split between CounterpartyInitiated/LocallyInitiated + CooperativeClosure, + /// A commitment transaction was confirmed on chain, closing the channel. Most likely this + /// commitment transaction came from our counterparty, but it may also have come from + /// a copy of our own `ChannelMonitor`. + CommitmentTxConfirmed, + /// Closure generated from processing an event, likely a HTLC forward/relay/reception. + ProcessingError { + /// A developer-readable error message which we generated. + err: String, + }, + /// The `PeerManager` informed us that we've disconnected from the peer. We close channels + /// if the `PeerManager` informed us that it is unlikely we'll be able to connect to the + /// peer again in the future or if the peer disconnected before we finished negotiating + /// the channel open. The first case may be caused by incompatible features which our + /// counterparty, or we, require. + //TODO: split between PeerUnconnectable/PeerDisconnected ? + DisconnectedPeer, + /// Closure generated from `ChannelManager::read` if the ChannelMonitor is newer than + /// the ChannelManager deserialized. + OutdatedChannelManager +} + +impl_writeable_tlv_based_enum_upgradable!(ClosureReason, + (0, CounterpartyForceClosed) => { (1, peer_msg, required) }, + (2, HolderForceClosed) => {}, + (6, CommitmentTxConfirmed) => {}, + (4, CooperativeClosure) => {}, + (8, ProcessingError) => { (1, err, required) }, + (10, DisconnectedPeer) => {}, + (12, OutdatedChannelManager) => {}, +); + /// 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 @@ -88,25 +147,27 @@ pub enum Event { channel_value_satoshis: u64, /// The script which should be used in the transaction output. output_script: Script, - /// The value passed in to ChannelManager::create_channel + /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`], or 0 for + /// an inbound channel. + /// + /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel user_channel_id: u64, }, /// Indicates we've received money! Just gotta dig out that payment preimage and feed it to - /// ChannelManager::claim_funds to get it.... - /// Note that if the preimage is not known or the amount paid is incorrect, you should call - /// ChannelManager::fail_htlc_backwards to free up resources for this HTLC and avoid + /// [`ChannelManager::claim_funds`] to get it.... + /// Note that if the preimage is not known, you should call + /// [`ChannelManager::fail_htlc_backwards`] to free up resources for this HTLC and avoid /// network congestion. - /// The amount paid should be considered 'incorrect' when it is less than or more than twice - /// the amount expected. - /// If you fail to call either ChannelManager::claim_funds or - /// ChannelManager::fail_htlc_backwards within the HTLC's timeout, the HTLC will be + /// If you fail to call either [`ChannelManager::claim_funds`] or + /// [`ChannelManager::fail_htlc_backwards`] within the HTLC's timeout, the HTLC will be /// automatically failed. + /// + /// [`ChannelManager::claim_funds`]: crate::ln::channelmanager::ChannelManager::claim_funds + /// [`ChannelManager::fail_htlc_backwards`]: crate::ln::channelmanager::ChannelManager::fail_htlc_backwards PaymentReceived { /// The hash for which the preimage should be handed to the ChannelManager. payment_hash: PaymentHash, - /// 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!). + /// The value, in thousandths of a satoshi, that this payment is for. amt: 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. @@ -115,17 +176,33 @@ pub enum Event { /// Indicates an outbound payment we made succeeded (i.e. it made it all the way to its target /// and we got back the payment preimage for it). /// - /// Note for MPP payments: in rare cases, this event may be preceded by a `PaymentFailed` event. - /// In this situation, you SHOULD treat this payment as having succeeded. + /// 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, /// 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! payment_preimage: PaymentPreimage, + /// The hash which was given to [`ChannelManager::send_payment`]. + /// + /// [`ChannelManager::send_payment`]: crate::ln::channelmanager::ChannelManager::send_payment + payment_hash: PaymentHash, }, /// Indicates an outbound payment we made failed. Probably some intermediary node dropped /// something. You may wish to retry with a different route. - PaymentFailed { + 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, /// 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 @@ -145,6 +222,20 @@ pub enum Event { /// failed. This will be set to false if (1) this is an MPP payment and (2) other parts of the /// larger MPP payment were still in flight when this event was generated. all_paths_failed: bool, + /// The payment path that failed. + path: Vec, + /// The channel responsible for the failed payment path. + /// + /// 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, + /// 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, #[cfg(test)] error_code: Option, #[cfg(test)] @@ -189,6 +280,28 @@ pub enum Event { /// transaction. claim_from_onchain_tx: bool, }, + /// Used to indicate that a channel with the given `channel_id` is in the process of closure. + ChannelClosed { + /// The channel_id of the channel which has been closed. Note that on-chain transactions + /// resolving the channel are likely still awaiting confirmation. + channel_id: [u8; 32], + /// The `user_channel_id` value passed in to [`ChannelManager::create_channel`], or 0 for + /// an inbound channel. This will always be zero for objects serialized with LDK versions + /// prior to 0.0.102. + /// + /// [`ChannelManager::create_channel`]: crate::ln::channelmanager::ChannelManager::create_channel + user_channel_id: u64, + /// The reason the channel was closed. + reason: ClosureReason + }, + /// Used to indicate to the user that they can abandon the funding transaction and recycle the + /// inputs for another purpose. + DiscardFunding { + /// The channel_id of the channel which has been closed. + channel_id: [u8; 32], + /// The full transaction received from the user + transaction: Transaction + } } impl Writeable for Event { @@ -222,13 +335,17 @@ impl Writeable for Event { (8, payment_preimage, option), }); }, - &Event::PaymentSent { ref payment_preimage } => { + &Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash} => { 2u8.write(writer)?; write_tlv_fields!(writer, { (0, payment_preimage, required), + (1, payment_hash, required), + (3, payment_id, option), }); }, - &Event::PaymentFailed { ref payment_hash, ref rejected_by_dest, ref network_update, ref all_paths_failed, + &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)] @@ -244,13 +361,16 @@ impl Writeable for Event { (1, network_update, option), (2, rejected_by_dest, required), (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: _ } => { 4u8.write(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. + // Note that we now ignore these on the read end as we'll re-generate them in + // ChannelManager, we write them here only for backwards compatibility. }, &Event::SpendableOutputs { ref outputs } => { 5u8.write(writer)?; @@ -265,6 +385,24 @@ impl Writeable for Event { (2, claim_from_onchain_tx, required), }); }, + &Event::ChannelClosed { ref channel_id, ref user_channel_id, ref reason } => { + 9u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (1, user_channel_id, required), + (2, reason, required) + }); + }, + &Event::DiscardFunding { ref channel_id, ref transaction } => { + 11u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, transaction, required) + }) + }, + // Note that, going forward, all new events must only write data inside of + // `write_tlv_fields`. Versions 0.0.101+ will ignore odd-numbered events that write + // data via `write_tlv_fields`. } Ok(()) } @@ -272,6 +410,8 @@ impl Writeable for Event { impl MaybeReadable for Event { fn read(reader: &mut R) -> Result, msgs::DecodeError> { match Readable::read(reader)? { + // Note that we do not write a length-prefixed TLV for FundingGenerationReady events, + // unlike all other events, thus we return immediately here. 0u8 => Ok(None), 1u8 => { let f = || { @@ -309,11 +449,20 @@ impl MaybeReadable for Event { 2u8 => { let f = || { let mut payment_preimage = PaymentPreimage([0; 32]); + let mut payment_hash = None; + let mut payment_id = None; read_tlv_fields!(reader, { (0, payment_preimage, required), + (1, payment_hash, option), + (3, payment_id, 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(), })) }; f() @@ -328,17 +477,29 @@ impl MaybeReadable for Event { let mut rejected_by_dest = false; let mut network_update = None; let mut all_paths_failed = Some(true); + let mut path: Option> = 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, option), + (9, retry, option), + (11, payment_id, option), }); - Ok(Some(Event::PaymentFailed { + 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)] @@ -347,15 +508,7 @@ impl MaybeReadable for Event { }; f() }, - 4u8 => { - let f = || { - read_tlv_fields!(reader, {}); - Ok(Some(Event::PendingHTLCsForwardable { - time_forwardable: Duration::from_secs(0) - })) - }; - f() - }, + 4u8 => Ok(None), 5u8 => { let f = || { let mut outputs = VecReadWrapper(Vec::new()); @@ -378,8 +531,48 @@ impl MaybeReadable for Event { }; f() }, + 9u8 => { + let f = || { + let mut channel_id = [0; 32]; + let mut reason = None; + let mut user_channel_id_opt = None; + read_tlv_fields!(reader, { + (0, channel_id, required), + (1, user_channel_id_opt, option), + (2, reason, ignorable), + }); + if reason.is_none() { return Ok(None); } + let user_channel_id = if let Some(id) = user_channel_id_opt { id } else { 0 }; + Ok(Some(Event::ChannelClosed { channel_id, user_channel_id, reason: reason.unwrap() })) + }; + f() + }, + 11u8 => { + let f = || { + let mut channel_id = [0; 32]; + let mut transaction = Transaction{ version: 2, lock_time: 0, input: Vec::new(), output: Vec::new() }; + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, transaction, required), + }); + Ok(Some(Event::DiscardFunding { channel_id, transaction } )) + }; + f() + }, // Versions prior to 0.0.100 did not ignore odd types, instead returning InvalidValue. - x if x % 2 == 1 => Ok(None), + // Version 0.0.100 failed to properly ignore odd types, possibly resulting in corrupt + // reads. + x if x % 2 == 1 => { + // If the event is of unknown type, assume it was written with `write_tlv_fields`, + // which prefixes the whole thing with a length BigSize. Because the event is + // odd-type unknown, we should treat it as `Ok(None)` even if it has some TLV + // fields that are even. Thus, we avoid using `read_tlv_fields` and simply read + // exactly the number of bytes specified, ignoring them entirely. + let tlv_len: BigSize = Readable::read(reader)?; + FixedLengthReader::new(reader, tlv_len.0) + .eat_remaining().map_err(|_| msgs::DecodeError::ShortRead)?; + Ok(None) + }, _ => Err(msgs::DecodeError::InvalidValue) } }