@@ -111,6 +111,7 @@ use crate::ln::script::ShutdownScript;
111111
112112/// Information about where a received HTLC('s onion) has indicated the HTLC should go.
113113#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
114+ #[cfg_attr(test, derive(Debug, PartialEq))]
114115pub enum PendingHTLCRouting {
115116 /// An HTLC which should be forwarded on to another node.
116117 Forward {
@@ -189,7 +190,7 @@ pub enum PendingHTLCRouting {
189190}
190191
191192/// Information used to forward or fail this HTLC that is being forwarded within a blinded path.
192- #[derive(Clone, Copy, Hash, PartialEq, Eq)]
193+ #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
193194pub struct BlindedForward {
194195 /// The `blinding_point` that was set in the inbound [`msgs::UpdateAddHTLC`], or in the inbound
195196 /// onion payload if we're the introduction node. Useful for calculating the next hop's
@@ -213,6 +214,7 @@ impl PendingHTLCRouting {
213214/// Information about an incoming HTLC, including the [`PendingHTLCRouting`] describing where it
214215/// should go next.
215216#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
217+ #[cfg_attr(test, derive(Debug, PartialEq))]
216218pub struct PendingHTLCInfo {
217219 /// Further routing details based on whether the HTLC is being forwarded or received.
218220 pub routing: PendingHTLCRouting,
@@ -267,6 +269,7 @@ pub(super) enum PendingHTLCStatus {
267269 Fail(HTLCFailureMsg),
268270}
269271
272+ #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
270273pub(super) struct PendingAddHTLCInfo {
271274 pub(super) forward_info: PendingHTLCInfo,
272275
@@ -282,6 +285,7 @@ pub(super) struct PendingAddHTLCInfo {
282285 prev_user_channel_id: u128,
283286}
284287
288+ #[cfg_attr(test, derive(Clone, Debug, PartialEq))]
285289pub(super) enum HTLCForwardInfo {
286290 AddHTLC(PendingAddHTLCInfo),
287291 FailHTLC {
@@ -11056,12 +11060,14 @@ mod tests {
1105611060 use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
1105711061 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
1105811062 use crate::ln::ChannelId;
11059- use crate::ln::channelmanager::{create_recv_pending_htlc_info, inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
11063+ use crate::ln::channelmanager::{create_recv_pending_htlc_info, HTLCForwardInfo, inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
1106011064 use crate::ln::functional_test_utils::*;
1106111065 use crate::ln::msgs::{self, ErrorAction};
1106211066 use crate::ln::msgs::ChannelMessageHandler;
11067+ use crate::prelude::*;
1106311068 use crate::routing::router::{PaymentParameters, RouteParameters, find_route};
1106411069 use crate::util::errors::APIError;
11070+ use crate::util::ser::Writeable;
1106511071 use crate::util::test_utils;
1106611072 use crate::util::config::{ChannelConfig, ChannelConfigUpdate};
1106711073 use crate::sign::EntropySource;
@@ -12336,6 +12342,63 @@ mod tests {
1233612342 check_spends!(txn[0], funding_tx);
1233712343 }
1233812344 }
12345+
12346+ #[test]
12347+ fn test_malformed_forward_htlcs_ser() {
12348+ // Ensure that `HTLCForwardInfo::FailMalformedHTLC`s are (de)serialized properly.
12349+ let chanmon_cfg = create_chanmon_cfgs(1);
12350+ let node_cfg = create_node_cfgs(1, &chanmon_cfg);
12351+ let persister;
12352+ let chain_monitor;
12353+ let chanmgrs = create_node_chanmgrs(1, &node_cfg, &[None]);
12354+ let deserialized_chanmgr;
12355+ let mut nodes = create_network(1, &node_cfg, &chanmgrs);
12356+
12357+ let dummy_failed_htlc = |htlc_id| {
12358+ HTLCForwardInfo::FailHTLC { htlc_id, err_packet: msgs::OnionErrorPacket { data: vec![42] }, }
12359+ };
12360+ let dummy_malformed_htlc = |htlc_id| {
12361+ HTLCForwardInfo::FailMalformedHTLC { htlc_id, failure_code: 0x4000, sha256_of_onion: [0; 32] }
12362+ };
12363+
12364+ let dummy_htlcs_1: Vec<HTLCForwardInfo> = (1..10).map(|htlc_id| {
12365+ if htlc_id % 2 == 0 {
12366+ dummy_failed_htlc(htlc_id)
12367+ } else {
12368+ dummy_malformed_htlc(htlc_id)
12369+ }
12370+ }).collect();
12371+
12372+ let dummy_htlcs_2: Vec<HTLCForwardInfo> = (1..10).map(|htlc_id| {
12373+ if htlc_id % 2 == 1 {
12374+ dummy_failed_htlc(htlc_id)
12375+ } else {
12376+ dummy_malformed_htlc(htlc_id)
12377+ }
12378+ }).collect();
12379+
12380+
12381+ let (scid_1, scid_2) = (42, 43);
12382+ let mut forward_htlcs = HashMap::new();
12383+ forward_htlcs.insert(scid_1, dummy_htlcs_1.clone());
12384+ forward_htlcs.insert(scid_2, dummy_htlcs_2.clone());
12385+
12386+ let mut chanmgr_fwd_htlcs = nodes[0].node.forward_htlcs.lock().unwrap();
12387+ *chanmgr_fwd_htlcs = forward_htlcs.clone();
12388+ core::mem::drop(chanmgr_fwd_htlcs);
12389+
12390+ reload_node!(nodes[0], nodes[0].node.encode(), &[], persister, chain_monitor, deserialized_chanmgr);
12391+
12392+ let mut deserialized_fwd_htlcs = nodes[0].node.forward_htlcs.lock().unwrap();
12393+ for scid in [scid_1, scid_2].iter() {
12394+ let deserialized_htlcs = deserialized_fwd_htlcs.remove(scid).unwrap();
12395+ assert_eq!(forward_htlcs.remove(scid).unwrap(), deserialized_htlcs);
12396+ }
12397+ assert!(deserialized_fwd_htlcs.is_empty());
12398+ core::mem::drop(deserialized_fwd_htlcs);
12399+
12400+ expect_pending_htlcs_forwardable!(nodes[0]);
12401+ }
1233912402}
1234012403
1234112404#[cfg(ldk_bench)]
0 commit comments