X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fevents.rs;h=798f562526fa8acbba55e4353e94c08b03d50980;hb=2d102a3065d7a438d5c88fffcad36545a0822bfa;hp=e810368dbc3a5b0066998fef1de3d4ef1f3e894c;hpb=53052234959a3c0a7323a194c351c4ba9b46339b;p=rust-lightning diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index e810368d..e9f456cf 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -1,29 +1,138 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + //! Events are returned from various bits in the library which indicate some action must be taken //! by the client. //! //! Because we don't have a built-in runtime, it's up to the client to call events at a time in the //! future, as well as generate and broadcast funding transactions handle payment preimages and a //! few other things. -//! -//! Note that many events are handled for you by PeerHandler, so in the common design of having a -//! PeerManager which marshalls messages to ChannelManager and Router you only need to call -//! process_events on the PeerHandler and then get_and_clear_pending_events and handle the events -//! that bubble up to the surface. If, however, you do not have a PeerHandler managing a -//! ChannelManager you need to handle all of the events which may be generated. -//TODO: We need better separation of event types ^ -use ln::msgs; -use ln::channelmanager::{PaymentPreimage, PaymentHash}; -use chain::transaction::OutPoint; 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::{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; -use secp256k1::key::PublicKey; +/// 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, + /// 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), +} + +#[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 +} -use std::time::Duration; +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 +/// them directly as they don't round-trip exactly (for example FundingGenerationReady is never +/// written as it makes no sense to respond to it after reconnecting to peers). +#[derive(Clone, Debug)] pub enum Event { /// Used to indicate that the client should generate a funding transaction with the given /// parameters and then call ChannelManager::funding_transaction_generated. @@ -38,56 +147,99 @@ 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 - user_channel_id: u64, - }, - /// Used to indicate that the client may now broadcast the funding transaction it created for a - /// channel. Broadcasting such a transaction prior to this event may lead to our counterparty - /// trivially stealing all funds in the funding transaction! - FundingBroadcastSafe { - /// The output, which was passed to ChannelManager::funding_transaction_generated, which is - /// now safe to broadcast. - funding_txo: OutPoint, - /// 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 must call - /// ChannelManager::fail_htlc_backwards to free up resources for this HTLC. - /// The amount paid should be considered 'incorrect' when it is less than or more than twice - /// the amount expected. + /// [`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. + /// 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. + purpose: PaymentPurpose, }, - /// Indicates an outbound payment we made succeeded (ie it made it all the way to its target + /// 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 that duplicative PaymentSent Events may be generated - it is your responsibility to - /// deduplicate them by payment_preimage (which MUST be unique)! + /// + /// 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. - /// Note that duplicative PaymentFailed Events may be generated - it is your responsibility to - /// deduplicate them by payment_hash (which MUST be unique)! - 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 /// the payment has failed, not just the route in question. If this is not set, you may /// retry the payment via a different route. rejected_by_dest: bool, + /// Any failure information conveyed via the Onion return packet by a node along the failed + /// payment route. + /// + /// Should be applied to the [`NetworkGraph`] so that routing decisions can take into + /// account the update. [`NetGraphMsgHandler`] is capable of doing this. + /// + /// [`NetworkGraph`]: crate::routing::network_graph::NetworkGraph + /// [`NetGraphMsgHandler`]: crate::routing::network_graph::NetGraphMsgHandler + network_update: Option, + /// For both single-path and multi-path payments, this is set if all paths of the payment have + /// 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)] + error_data: Option>, }, /// Used to indicate that ChannelManager::process_pending_htlc_forwards should be called at a /// time in the future. @@ -98,19 +250,338 @@ pub enum Event { /// now + 5*time_forwardable). time_forwardable: Duration, }, - /// Used to indicate that an output was generated on-chain which you should know how to spend. - /// Such an output will *not* ever be spent by rust-lightning, so you need to store them - /// somewhere and spend them when you create on-chain spends. + /// 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. SpendableOutputs { /// The outputs which you should store as spendable by you. outputs: Vec, }, + /// 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, + /// If this is `true`, the forwarded HTLC was claimed by our counterparty via an on-chain + /// 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 { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + match self { + &Event::FundingGenerationReady { .. } => { + 0u8.write(writer)?; + // 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 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, required), + (2, payment_secret, option), + (4, amt, required), + (6, user_payment_id, option), + (8, payment_preimage, option), + }); + }, + &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::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)] + ref error_data, + } => { + 3u8.write(writer)?; + #[cfg(test)] + error_code.write(writer)?; + #[cfg(test)] + error_data.write(writer)?; + write_tlv_fields!(writer, { + (0, payment_hash, required), + (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)?; + // 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)?; + write_tlv_fields!(writer, { + (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), + }); + }, + &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(()) + } +} +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 = || { + let mut payment_hash = PaymentHash([0; 32]); + let mut payment_preimage = None; + let mut payment_secret = None; + let mut amt = 0; + let mut user_payment_id = None; + read_tlv_fields!(reader, { + (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, + amt, + purpose, + })) + }; + f() + }, + 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() + }, + 3u8 => { + let f = || { + #[cfg(test)] + let error_code = Readable::read(reader)?; + #[cfg(test)] + let error_data = Readable::read(reader)?; + let mut payment_hash = PaymentHash([0; 32]); + 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::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)] + error_data, + })) + }; + f() + }, + 4u8 => Ok(None), + 5u8 => { + let f = || { + let mut outputs = VecReadWrapper(Vec::new()); + read_tlv_fields!(reader, { + (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() + }, + 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. + // 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) + } + } } /// An event generated by ChannelManager which indicates a message should be sent to a peer (or /// broadcast to most peers). /// These events are handled by PeerManager::process_events if you are using a PeerManager. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum MessageSendEvent { /// Used to indicate that we've accepted a channel open and should send the accept_channel /// message provided to the given peer. @@ -194,17 +665,37 @@ pub enum MessageSendEvent { }, /// Used to indicate that a channel_announcement and channel_update should be broadcast to all /// peers (except the peer with node_id either msg.contents.node_id_1 or msg.contents.node_id_2). + /// + /// Note that after doing so, you very likely (unless you did so very recently) want to call + /// ChannelManager::broadcast_node_announcement to trigger a BroadcastNodeAnnouncement event. + /// This ensures that any nodes which see our channel_announcement also have a relevant + /// node_announcement, including relevant feature flags which may be important for routing + /// through or to us. BroadcastChannelAnnouncement { /// The channel_announcement which should be sent. msg: msgs::ChannelAnnouncement, /// The followup channel_update which should be sent. update_msg: msgs::ChannelUpdate, }, + /// Used to indicate that a node_announcement should be broadcast to all peers. + BroadcastNodeAnnouncement { + /// The node_announcement which should be sent. + msg: msgs::NodeAnnouncement, + }, /// Used to indicate that a channel_update should be broadcast to all peers. BroadcastChannelUpdate { /// 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 @@ -212,11 +703,28 @@ pub enum MessageSendEvent { /// The action which should be taken. action: msgs::ErrorAction }, - /// When a payment fails we may receive updates back from the hop where it failed. In such - /// cases this event is generated so that we can inform the router of this information. - PaymentFailureNetworkUpdate { - /// The channel/node update which should be sent to router - update: msgs::HTLCFailChannelUpdate, + /// Query a peer for channels with funding transaction UTXOs in a block range. + SendChannelRangeQuery { + /// The node_id of this message recipient + node_id: PublicKey, + /// The query_channel_range which should be sent. + msg: msgs::QueryChannelRange, + }, + /// Request routing gossip messages from a peer for a list of channels identified by + /// their short_channel_ids. + SendShortIdsQuery { + /// The node_id of this message recipient + node_id: PublicKey, + /// The query_short_channel_ids which should be sent. + msg: msgs::QueryShortChannelIds, + }, + /// Sends a reply to a channel range query. This may be one of several SendReplyChannelRange events + /// emitted during processing of the query. + SendReplyChannelRange { + /// The node_id of this message recipient + node_id: PublicKey, + /// The reply_channel_range which should be sent. + msg: msgs::ReplyChannelRange, } } @@ -227,9 +735,49 @@ pub trait MessageSendEventsProvider { fn get_and_clear_pending_msg_events(&self) -> Vec; } -/// A trait indicating an object may generate events +/// A trait indicating an object may generate events. +/// +/// Events are processed by passing an [`EventHandler`] to [`process_pending_events`]. +/// +/// # Requirements +/// +/// See [`process_pending_events`] for requirements around event processing. +/// +/// When using this trait, [`process_pending_events`] will call [`handle_event`] for each pending +/// event since the last invocation. The handler must either act upon the event immediately +/// or preserve it for later handling. +/// +/// Note, handlers may call back into the provider and thus deadlocking must be avoided. Be sure to +/// consult the provider's documentation on the implication of processing events and how a handler +/// may safely use the provider (e.g., see [`ChannelManager::process_pending_events`] and +/// [`ChainMonitor::process_pending_events`]). +/// +/// (C-not implementable) As there is likely no reason for a user to implement this trait on their +/// own type(s). +/// +/// [`process_pending_events`]: Self::process_pending_events +/// [`handle_event`]: EventHandler::handle_event +/// [`ChannelManager::process_pending_events`]: crate::ln::channelmanager::ChannelManager#method.process_pending_events +/// [`ChainMonitor::process_pending_events`]: crate::chain::chainmonitor::ChainMonitor#method.process_pending_events pub trait EventsProvider { - /// Gets the list of pending events which were generated by previous actions, clearing the list - /// in the process. - fn get_and_clear_pending_events(&self) -> Vec; + /// Processes any events generated since the last call using the given event handler. + /// + /// Subsequent calls must only process new events. However, handlers must be capable of handling + /// duplicate events across process restarts. This may occur if the provider was recovered from + /// an old state (i.e., it hadn't been successfully persisted after processing pending events). + fn process_pending_events(&self, handler: H) where H::Target: EventHandler; +} + +/// A trait implemented for objects handling events from [`EventsProvider`]. +pub trait EventHandler { + /// Handles the given [`Event`]. + /// + /// See [`EventsProvider`] for details that must be considered when implementing this method. + fn handle_event(&self, event: &Event); +} + +impl EventHandler for F where F: Fn(&Event) { + fn handle_event(&self, event: &Event) { + self(event) + } }