X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=ef73db8eb813b2dea164cc00a4b245924c1898a1;hb=f47ba769f544c4fd2e2d1aa0bd5b1fa74ae15daa;hp=61df7a018bee6ba0ba4f2f34697581b93c2efce7;hpb=f9fc2dfbe20f86ab8bc3e637f3ca33a5a868cb98;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 61df7a01..ef73db8e 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -374,7 +374,7 @@ impl Channel { if msg.htlc_minimum_msat >= (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000 { return Err(HandleError{err: "Minimum htlc value is full channel value", msg: None}); } - Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw).unwrap(); + Channel::check_remote_fee(fee_estimator, msg.feerate_per_kw)?; if msg.to_self_delay > MAX_LOCAL_BREAKDOWN_TIMEOUT { return Err(HandleError{err: "They wanted our payments to be delayed by a needlessly long period", msg: None}); } @@ -782,8 +782,9 @@ impl Channel { return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None}); } + //TODO: This is racy af, they may have pending messages in flight to us that will not have + //received this yet! self.value_to_self_msat += htlc_amount_msat; - Ok(msgs::UpdateFulfillHTLC { channel_id: self.channel_id(), htlc_id: htlc_id, @@ -791,6 +792,37 @@ impl Channel { }) } + pub fn get_update_fail_htlc(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result { + if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { + return Err(HandleError{err: "Was asked to fail an HTLC when channel was not in an operational state", msg: None}); + } + + let mut htlc_id = 0; + let mut htlc_amount_msat = 0; + self.pending_htlcs.retain(|ref htlc| { + if !htlc.outbound && htlc.payment_hash == *payment_hash { + 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; + false + } else { true } + }); + if htlc_amount_msat == 0 { + return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None}); + } + + //TODO: This is racy af, they may have pending messages in flight to us that will not have + //received this yet! + + Ok(msgs::UpdateFailHTLC { + channel_id: self.channel_id(), + htlc_id, + reason: err_packet + }) + } + // Message handlers: pub fn accept_channel(&mut self, msg: &msgs::AcceptChannel) -> Result<(), HandleError> { @@ -1010,7 +1042,7 @@ impl Channel { } /// Removes an outbound HTLC which has been commitment_signed by the remote end - fn remove_htlc(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>) -> Result { + fn remove_outbound_htlc(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>) -> Result { let mut found_idx = None; for (idx, ref htlc) in self.pending_htlcs.iter().enumerate() { if htlc.outbound && htlc.htlc_id == htlc_id { @@ -1026,7 +1058,7 @@ impl Channel { } } match found_idx { - None => Err(HandleError{err: "Remote tried to fulfill an HTLC we couldn't find", msg: None}), + None => Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: None}), Some(idx) => { Ok(self.pending_htlcs.swap_remove(idx)) } @@ -1096,9 +1128,7 @@ impl Channel { let mut payment_hash = [0; 32]; sha.result(&mut payment_hash); - //TODO: Tell channel_monitor about the payment_preimage - - match self.remove_htlc(msg.htlc_id, Some(payment_hash)) { + match self.remove_outbound_htlc(msg.htlc_id, Some(payment_hash)) { Err(e) => return Err(e), Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went @@ -1110,43 +1140,40 @@ impl Channel { self.check_and_free_holding_cell_htlcs() } - - pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { + pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC) -> Result<([u8; 32], Option<(Vec, msgs::CommitmentSigned)>), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None}); } - //TODO: Lots of checks here (and implementation after the remove?) - - match self.remove_htlc(msg.htlc_id, None) { + let payment_hash = match self.remove_outbound_htlc(msg.htlc_id, None) { Err(e) => return Err(e), - Ok(_htlc) => { + Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went //negative here?) - ////TODO: Something? + htlc.payment_hash } - } + }; - self.check_and_free_holding_cell_htlcs() + let holding_cell_freedom = self.check_and_free_holding_cell_htlcs()?; + Ok((payment_hash, holding_cell_freedom)) } - pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC) -> Result, msgs::CommitmentSigned)>, HandleError> { + pub fn update_fail_malformed_htlc(&mut self, msg: &msgs::UpdateFailMalformedHTLC) -> Result<([u8; 32], Option<(Vec, msgs::CommitmentSigned)>), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None}); } - //TODO: Lots of checks here (and implementation after the remove?) - - match self.remove_htlc(msg.htlc_id, None) { + let payment_hash = match self.remove_outbound_htlc(msg.htlc_id, None) { Err(e) => return Err(e), - Ok(_htlc) => { + Ok(htlc) => { //TODO: Double-check that we didn't exceed some limits (or value_to_self went //negative here?) - ////TODO: Something? + htlc.payment_hash } - } + }; - self.check_and_free_holding_cell_htlcs() + let holding_cell_freedom = self.check_and_free_holding_cell_htlcs()?; + Ok((payment_hash, holding_cell_freedom)) } pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Vec), HandleError> {