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;
use bitcoin::blockdata::script::Script;
/// 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 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
},
/// 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 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
/// 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<RouteHop>,
#[cfg(test)]
error_code: Option<u16>,
#[cfg(test)]
(0, payment_preimage, required),
});
},
- &Event::PaymentFailed { ref payment_hash, ref rejected_by_dest, ref network_update, ref all_paths_failed,
+ &Event::PaymentPathFailed { ref payment_hash, ref rejected_by_dest, ref network_update,
+ ref all_paths_failed, ref path,
#[cfg(test)]
ref error_code,
#[cfg(test)]
(1, network_update, option),
(2, rejected_by_dest, required),
(3, all_paths_failed, required),
+ (5, path, vec_type),
});
},
&Event::PendingHTLCsForwardable { time_forwardable: _ } => {
(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(())
}
impl MaybeReadable for Event {
fn read<R: io::Read>(reader: &mut R) -> Result<Option<Self>, 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 rejected_by_dest = false;
let mut network_update = None;
let mut all_paths_failed = Some(true);
+ let mut path: Option<Vec<RouteHop>> = Some(vec![]);
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),
});
- Ok(Some(Event::PaymentFailed {
+ Ok(Some(Event::PaymentPathFailed {
payment_hash,
rejected_by_dest,
network_update,
all_paths_failed: all_paths_failed.unwrap(),
+ path: path.unwrap(),
#[cfg(test)]
error_code,
#[cfg(test)]
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)
}
}