X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fevents.rs;h=be9296161768314aeae20da5feecdd69eeb8fa76;hb=5262e77ae186e4ea58294a7c6ee05e5649a12fc5;hp=df4d9037307c30cb20e32c9b36a07ff6c10cd4b5;hpb=831f124721413323c32e523378969d119dd16526;p=rust-lightning diff --git a/lightning/src/util/events.rs b/lightning/src/util/events.rs index df4d9037..be929616 100644 --- a/lightning/src/util/events.rs +++ b/lightning/src/util/events.rs @@ -16,9 +16,10 @@ use chain::keysinterface::SpendableOutputDescriptor; 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 bitcoin::blockdata::script::Script; @@ -68,6 +69,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 @@ -189,6 +244,14 @@ 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 reason the channel was closed. + reason: ClosureReason + } } impl Writeable for Event { @@ -265,6 +328,16 @@ impl Writeable for Event { (2, claim_from_onchain_tx, required), }); }, + &Event::ChannelClosed { ref channel_id, ref reason } => { + 9u8.write(writer)?; + write_tlv_fields!(writer, { + (0, channel_id, required), + (2, reason, 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 +345,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 = || { @@ -378,8 +453,30 @@ impl MaybeReadable for Event { }; f() }, + 9u8 => { + let mut channel_id = [0; 32]; + let mut reason = None; + read_tlv_fields!(reader, { + (0, channel_id, required), + (2, reason, ignorable), + }); + if reason.is_none() { return Ok(None); } + Ok(Some(Event::ChannelClosed { channel_id, reason: reason.unwrap() })) + }, // 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) } }