X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=44875fcd698089c4d8e9966b195c105fb1eebfb8;hb=4ca5bcf8cfc5cb3868974028b23ab7829c21426b;hp=a54be7722384fd2da84ed7de9c801d48e7a527be;hpb=11e5975523147ae7024b03f05445c78c9b695752;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index a54be772..44875fcd 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -16,7 +16,7 @@ use crypto::hkdf::{hkdf_extract,hkdf_expand}; use ln::msgs; use ln::msgs::{ErrorAction, HandleError, MsgEncodable}; use ln::channelmonitor::ChannelMonitor; -use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason}; +use ln::channelmanager::{PendingHTLCStatus, PendingForwardHTLCInfo, HTLCFailReason, HTLCFailureMsg}; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; @@ -164,7 +164,7 @@ struct HTLCOutput { //TODO: Refactor into Outbound/InboundHTLCOutput (will save /// If we're in LocalRemoved*, set to true if we fulfilled the HTLC, and can claim money local_removed_fulfilled: bool, /// state pre-committed Remote* implies pending_forward_state, otherwise it must be None - pending_forward_state: Option, + pending_forward_state: Option, } impl HTLCOutput { @@ -1018,10 +1018,13 @@ impl Channel { for (idx, htlc) in self.pending_htlcs.iter().enumerate() { if !htlc.outbound && htlc.payment_hash == payment_hash_calc && htlc.state != HTLCState::LocalRemoved && htlc.state != HTLCState::LocalRemovedAwaitingCommitment { - if pending_idx != std::usize::MAX { - panic!("Duplicate HTLC payment_hash, ChannelManager should have prevented this!"); + if let Some(PendingHTLCStatus::Fail(_)) = htlc.pending_forward_state { + } else { + if pending_idx != std::usize::MAX { + panic!("Duplicate HTLC payment_hash, ChannelManager should have prevented this!"); + } + pending_idx = idx; } - pending_idx = idx; } } if pending_idx == std::usize::MAX { @@ -1131,17 +1134,24 @@ impl Channel { if htlc_id != 0 { panic!("Duplicate HTLC payment_hash, you probably re-used payment preimages, NEVER DO THIS!"); } - htlc_id = htlc.htlc_id; - htlc_amount_msat += htlc.amount_msat; if htlc.state == HTLCState::Committed { htlc.state = HTLCState::LocalRemoved; } else if htlc.state == HTLCState::RemoteAnnounced { - panic!("Somehow forwarded HTLC prior to remote revocation!"); + if let Some(PendingHTLCStatus::Forward(_)) = htlc.pending_forward_state { + panic!("Somehow forwarded HTLC prior to remote revocation!"); + } else { + // We have to pretend this isn't here - we're probably a duplicate with the + // same payment_hash as some other HTLC, and the other is getting failed, + // we'll fail this one as soon as remote commits to it. + continue; + } } else if htlc.state == HTLCState::LocalRemoved || htlc.state == HTLCState::LocalRemovedAwaitingCommitment { return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", action: None}); } else { panic!("Have an inbound HTLC when not awaiting remote revoke that had a garbage state"); } + htlc_id = htlc.htlc_id; + htlc_amount_msat += htlc.amount_msat; } } if htlc_amount_msat == 0 { @@ -1381,7 +1391,7 @@ impl Channel { (inbound_htlc_count, outbound_htlc_count, htlc_outbound_value_msat, htlc_inbound_value_msat) } - pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingForwardHTLCInfo) -> Result<(), HandleError> { + pub fn update_add_htlc(&mut self, msg: &msgs::UpdateAddHTLC, pending_forward_state: PendingHTLCStatus) -> Result<(), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32 | ChannelState::RemoteShutdownSent as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", action: None}); } @@ -1633,6 +1643,7 @@ impl Channel { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, + update_fail_malformed_htlcs: Vec::new(), commitment_signed, }, monitor_update))) }, @@ -1670,6 +1681,8 @@ impl Channel { let mut to_forward_infos = Vec::new(); let mut revoked_htlcs = Vec::new(); + let mut update_fail_htlcs = Vec::new(); + let mut update_fail_malformed_htlcs = Vec::new(); let mut require_commitment = false; let mut value_to_self_msat_diff: i64 = 0; // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug) @@ -1693,8 +1706,20 @@ impl Channel { htlc.state = HTLCState::AwaitingAnnouncedRemoteRevoke; require_commitment = true; } else if htlc.state == HTLCState::AwaitingAnnouncedRemoteRevoke { - htlc.state = HTLCState::Committed; - to_forward_infos.push(htlc.pending_forward_state.take().unwrap()); + match htlc.pending_forward_state.take().unwrap() { + PendingHTLCStatus::Fail(fail_msg) => { + htlc.state = HTLCState::LocalRemoved; + require_commitment = true; + match fail_msg { + HTLCFailureMsg::Relay(msg) => update_fail_htlcs.push(msg), + HTLCFailureMsg::Malformed(msg) => update_fail_malformed_htlcs.push(msg), + } + }, + PendingHTLCStatus::Forward(forward_info) => { + to_forward_infos.push(forward_info); + htlc.state = HTLCState::Committed; + } + } } else if htlc.state == HTLCState::AwaitingRemoteRevokeToRemove { htlc.state = HTLCState::AwaitingRemovedRemoteRevoke; require_commitment = true; @@ -1706,7 +1731,15 @@ impl Channel { self.value_to_self_msat = (self.value_to_self_msat as i64 + value_to_self_msat_diff) as u64; match self.free_holding_cell_htlcs()? { - Some(commitment_update) => { + Some(mut commitment_update) => { + commitment_update.0.update_fail_htlcs.reserve(update_fail_htlcs.len()); + for fail_msg in update_fail_htlcs.drain(..) { + commitment_update.0.update_fail_htlcs.push(fail_msg); + } + commitment_update.0.update_fail_malformed_htlcs.reserve(update_fail_malformed_htlcs.len()); + for fail_msg in update_fail_malformed_htlcs.drain(..) { + commitment_update.0.update_fail_malformed_htlcs.push(fail_msg); + } Ok((Some(commitment_update.0), to_forward_infos, revoked_htlcs, commitment_update.1)) }, None => { @@ -1715,7 +1748,8 @@ impl Channel { Ok((Some(msgs::CommitmentUpdate { update_add_htlcs: Vec::new(), update_fulfill_htlcs: Vec::new(), - update_fail_htlcs: Vec::new(), + update_fail_htlcs, + update_fail_malformed_htlcs, commitment_signed }), to_forward_infos, revoked_htlcs, monitor_update)) } else {