X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=2dc7750e472be7d02a1a85fc2d109cb3a7031a67;hb=dc4a8c1de248a668a37a370264f094bc041d5efe;hp=1e28c6f463f3a348b198cd911efabc1ab87d5c82;hpb=eff730af18f78f48307732e7265b2411d7f25e21;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 1e28c6f4..2dc7750e 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -330,6 +330,7 @@ pub(super) struct Channel { our_dust_limit_satoshis: u64, their_max_htlc_value_in_flight_msat: u64, //get_our_max_htlc_value_in_flight_msat(): u64, + /// minimum channel reserve for **self** to maintain - set by them. their_channel_reserve_satoshis: u64, //get_our_channel_reserve_satoshis(): u64, their_htlc_minimum_msat: u64, @@ -402,6 +403,8 @@ impl Channel { channel_value_satoshis * 1000 / 10 //TODO } + /// Returns a minimum channel reserve value **they** need to maintain + /// /// Guaranteed to return a value no larger than channel_value_satoshis fn get_our_channel_reserve_satoshis(channel_value_satoshis: u64) -> u64 { let (q, _) = channel_value_satoshis.overflowing_div(100); @@ -1467,7 +1470,7 @@ impl Channel { return Err(HandleError{err: "Remote side tried to send less than our minimum HTLC value", action: None}); } - let (inbound_htlc_count, _, htlc_outbound_value_msat, htlc_inbound_value_msat) = self.get_pending_htlc_stats(true); + let (inbound_htlc_count, _, _, htlc_inbound_value_msat) = self.get_pending_htlc_stats(true); if inbound_htlc_count + 1 > OUR_MAX_HTLCS as u32 { return Err(HandleError{err: "Remote tried to push more than our max accepted HTLCs", action: None}); } @@ -1479,7 +1482,7 @@ impl Channel { // Check our_channel_reserve_satoshis (we're getting paid, so they have to at least meet // the reserve_satoshis we told them to always have as direct payment so that they lose // something if we punish them for broadcasting an old state). - if htlc_inbound_value_msat + htlc_outbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 { + if htlc_inbound_value_msat + msg.amount_msat + self.value_to_self_msat > (self.channel_value_satoshis - Channel::get_our_channel_reserve_satoshis(self.channel_value_satoshis)) * 1000 { return Err(HandleError{err: "Remote HTLC add would put them over their reserve value", action: None}); } if self.next_remote_htlc_id != msg.htlc_id { @@ -2722,7 +2725,7 @@ impl Channel { return Err(HandleError{err: "Cannot send an HTLC while disconnected", action: Some(ErrorAction::IgnoreError)}); } - let (_, outbound_htlc_count, htlc_outbound_value_msat, htlc_inbound_value_msat) = self.get_pending_htlc_stats(false); + let (_, outbound_htlc_count, htlc_outbound_value_msat, _) = self.get_pending_htlc_stats(false); if outbound_htlc_count + 1 > self.their_max_accepted_htlcs as u32 { return Err(HandleError{err: "Cannot push more than their max accepted HTLCs", action: None}); } @@ -2731,8 +2734,20 @@ impl Channel { if htlc_outbound_value_msat + amount_msat > self.their_max_htlc_value_in_flight_msat { return Err(HandleError{err: "Cannot send value that would put us over our max HTLC value in flight", action: None}); } - // Check their_channel_reserve_satoshis: - if htlc_inbound_value_msat + htlc_outbound_value_msat + amount_msat + (self.channel_value_satoshis * 1000 - self.value_to_self_msat) > (self.channel_value_satoshis - self.their_channel_reserve_satoshis) * 1000 { + + let mut holding_cell_outbound_amount_msat = 0; + for holding_htlc in self.holding_cell_htlc_updates.iter() { + match holding_htlc { + &HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, .. } => { + holding_cell_outbound_amount_msat += *amount_msat; + } + _ => {} + } + } + + // Check self.their_channel_reserve_satoshis (the amount we must keep as + // reserve for them to have something to claim if we misbehave) + if self.value_to_self_msat < self.their_channel_reserve_satoshis * 1000 + amount_msat + holding_cell_outbound_amount_msat + htlc_outbound_value_msat { return Err(HandleError{err: "Cannot send value that would put us over our reserve value", action: None}); } @@ -2886,11 +2901,16 @@ impl Channel { } } if self.channel_state & BOTH_SIDES_SHUTDOWN_MASK != 0 { - return Err(APIError::APIMisuseError{err: "Shutdown already in progress"}); + if (self.channel_state & ChannelState::LocalShutdownSent as u32) == ChannelState::LocalShutdownSent as u32 { + return Err(APIError::APIMisuseError{err: "Shutdown already in progress"}); + } + else if (self.channel_state & ChannelState::RemoteShutdownSent as u32) == ChannelState::RemoteShutdownSent as u32 { + return Err(APIError::ChannelUnavailable{err: "Shutdown already in progress by remote"}); + } } assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { - return Err(APIError::APIMisuseError{err: "Cannot begin shutdown while peer is disconnected, maybe force-close instead?"}); + return Err(APIError::ChannelUnavailable{err: "Cannot begin shutdown while peer is disconnected, maybe force-close instead?"}); } let our_closing_script = self.get_closing_scriptpubkey();