X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannel.rs;h=74728e3a96fd7f0290aae550c9909a8a4b977469;hb=bb094f1e30ad449149b78edcf294ff99bbd2d8d9;hp=92469b4fa8d714a1be39aa3e9363685b4ac32f45;hpb=b2252fb1e4e9d6c1b37e64d28d8777f5f5374260;p=rust-lightning diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 92469b4f..74728e3a 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -2,13 +2,14 @@ use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType}; use bitcoin::blockdata::opcodes; -use bitcoin::util::hash::{BitcoinHash, Sha256dHash}; +use bitcoin::util::hash::BitcoinHash; use bitcoin::util::bip143; use bitcoin::consensus::encode::{self, Encodable, Decodable}; use bitcoin_hashes::{Hash, HashEngine}; use bitcoin_hashes::sha256::Hash as Sha256; use bitcoin_hashes::hash160::Hash as Hash160; +use bitcoin_hashes::sha256d::Hash as Sha256dHash; use secp256k1::key::{PublicKey,SecretKey}; use secp256k1::{Secp256k1,Signature}; @@ -25,7 +26,7 @@ use chain::transaction::OutPoint; use chain::keysinterface::{ChannelKeys, KeysInterface}; use util::transaction_utils; use util::ser::{Readable, ReadableArgs, Writeable, Writer, WriterWriteAdaptor}; -use util::logger::Logger; +use util::logger::{Logger, LogHolder}; use util::errors::APIError; use util::config::{UserConfig,ChannelConfig}; @@ -106,19 +107,19 @@ enum OutboundHTLCState { Committed, /// Remote removed this (outbound) HTLC. We're waiting on their commitment_signed to finalize /// the change (though they'll need to revoke before we fail the payment). - RemoteRemoved, + RemoteRemoved(Option), /// Remote removed this and sent a commitment_signed (implying we've revoke_and_ack'ed it), but /// the remote side hasn't yet revoked their previous state, which we need them to do before we /// can do any backwards failing. Implies AwaitingRemoteRevoke. /// We also have not yet removed this HTLC in a commitment_signed message, and are waiting on a /// remote revoke_and_ack on a previous state before we can do so. - AwaitingRemoteRevokeToRemove, + AwaitingRemoteRevokeToRemove(Option), /// Remote removed this and sent a commitment_signed (implying we've revoke_and_ack'ed it), but /// the remote side hasn't yet revoked their previous state, which we need them to do before we /// can do any backwards failing. Implies AwaitingRemoteRevoke. /// We have removed this HTLC in our latest commitment_signed and are now just waiting on a /// revoke_and_ack to drop completely. - AwaitingRemovedRemoteRevoke, + AwaitingRemovedRemoteRevoke(Option), } struct OutboundHTLCOutput { @@ -128,8 +129,6 @@ struct OutboundHTLCOutput { payment_hash: PaymentHash, state: OutboundHTLCState, source: HTLCSource, - /// If we're in a removed state, set if they failed, otherwise None - fail_reason: Option, } /// See AwaitingRemoteRevoke ChannelState for more info @@ -858,9 +857,9 @@ impl Channel { let (include, state_name) = match htlc.state { OutboundHTLCState::LocalAnnounced(_) => (generated_by_local, "LocalAnnounced"), OutboundHTLCState::Committed => (true, "Committed"), - OutboundHTLCState::RemoteRemoved => (generated_by_local, "RemoteRemoved"), - OutboundHTLCState::AwaitingRemoteRevokeToRemove => (generated_by_local, "AwaitingRemoteRevokeToRemove"), - OutboundHTLCState::AwaitingRemovedRemoteRevoke => (false, "AwaitingRemovedRemoteRevoke"), + OutboundHTLCState::RemoteRemoved(_) => (generated_by_local, "RemoteRemoved"), + OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) => (generated_by_local, "AwaitingRemoteRevokeToRemove"), + OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) => (false, "AwaitingRemovedRemoteRevoke"), }; if include { @@ -869,13 +868,11 @@ impl Channel { } else { log_trace!(self, " ...not including outbound HTLC {} (hash {}) with value {} due to state ({})", htlc.htlc_id, log_bytes!(htlc.payment_hash.0), htlc.amount_msat, state_name); match htlc.state { - OutboundHTLCState::AwaitingRemoteRevokeToRemove|OutboundHTLCState::AwaitingRemovedRemoteRevoke => { - if htlc.fail_reason.is_none() { - value_to_self_msat_offset -= htlc.amount_msat as i64; - } + OutboundHTLCState::AwaitingRemoteRevokeToRemove(None)|OutboundHTLCState::AwaitingRemovedRemoteRevoke(None) => { + value_to_self_msat_offset -= htlc.amount_msat as i64; }, - OutboundHTLCState::RemoteRemoved => { - if !generated_by_local && htlc.fail_reason.is_none() { + OutboundHTLCState::RemoteRemoved(None) => { + if !generated_by_local { value_to_self_msat_offset -= htlc.amount_msat as i64; } }, @@ -1225,6 +1222,7 @@ impl Channel { _ => {} } } + log_trace!(self, "Adding HTLC claim to holding_cell! Current state: {}", self.channel_state); self.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage: payment_preimage_arg, htlc_id: htlc_id_arg, }); @@ -1238,6 +1236,7 @@ impl Channel { debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); return Ok((None, Some(self.channel_monitor.clone()))); } + log_trace!(self, "Upgrading HTLC {} to LocalRemoved with a Fulfill!", log_bytes!(htlc.payment_hash.0)); htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone())); } @@ -1642,10 +1641,9 @@ impl Channel { OutboundHTLCState::LocalAnnounced(_) => return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC before it had been committed")), OutboundHTLCState::Committed => { - htlc.state = OutboundHTLCState::RemoteRemoved; - htlc.fail_reason = fail_reason; + htlc.state = OutboundHTLCState::RemoteRemoved(fail_reason); }, - OutboundHTLCState::AwaitingRemoteRevokeToRemove | OutboundHTLCState::AwaitingRemovedRemoteRevoke | OutboundHTLCState::RemoteRemoved => + OutboundHTLCState::AwaitingRemoteRevokeToRemove(_) | OutboundHTLCState::AwaitingRemovedRemoteRevoke(_) | OutboundHTLCState::RemoteRemoved(_) => return Err(ChannelError::Close("Remote tried to fulfill/fail HTLC that they'd already fulfilled/failed")), } return Ok(&htlc.source); @@ -1798,8 +1796,10 @@ impl Channel { } } for htlc in self.pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::RemoteRemoved = htlc.state { - htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove; + if let Some(fail_reason) = if let &mut OutboundHTLCState::RemoteRemoved(ref mut fail_reason) = &mut htlc.state { + Some(fail_reason.take()) + } else { None } { + htlc.state = OutboundHTLCState::AwaitingRemoteRevokeToRemove(fail_reason); need_our_commitment = true; } } @@ -1852,6 +1852,8 @@ impl Channel { fn free_holding_cell_htlcs(&mut self) -> Result, ChannelError> { assert_eq!(self.channel_state & ChannelState::MonitorUpdateFailed as u32, 0); if self.holding_cell_htlc_updates.len() != 0 || self.holding_cell_update_fee.is_some() { + log_trace!(self, "Freeing holding cell with {} HTLC updates{}", self.holding_cell_htlc_updates.len(), if self.holding_cell_update_fee.is_some() { " and a fee update" } else { "" }); + let mut htlc_updates = Vec::new(); mem::swap(&mut htlc_updates, &mut self.holding_cell_htlc_updates); let mut update_add_htlcs = Vec::with_capacity(htlc_updates.len()); @@ -1992,74 +1994,92 @@ impl Channel { self.monitor_pending_order = None; } + log_trace!(self, "Updating HTLCs on receipt of RAA..."); 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) - self.pending_inbound_htlcs.retain(|htlc| { - if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state { - if let &InboundHTLCRemovalReason::Fulfill(_) = reason { - value_to_self_msat_diff += htlc.amount_msat as i64; - } - false - } else { true } - }); - self.pending_outbound_htlcs.retain(|htlc| { - if let OutboundHTLCState::AwaitingRemovedRemoteRevoke = htlc.state { - if let Some(reason) = htlc.fail_reason.clone() { // We really want take() here, but, again, non-mut ref :( - revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason)); - } else { - // They fulfilled, so we sent them money - value_to_self_msat_diff -= htlc.amount_msat as i64; - } - false - } else { true } - }); - for htlc in self.pending_inbound_htlcs.iter_mut() { - let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state { - true - } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state { - true - } else { false }; - if swap { - let mut state = InboundHTLCState::Committed; - mem::swap(&mut state, &mut htlc.state); - - if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state { - htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info); - require_commitment = true; - } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state { - match forward_info { - PendingHTLCStatus::Fail(fail_msg) => { - require_commitment = true; - match fail_msg { - HTLCFailureMsg::Relay(msg) => { - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone())); - update_fail_htlcs.push(msg) - }, - HTLCFailureMsg::Malformed(msg) => { - htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code))); - update_fail_malformed_htlcs.push(msg) - }, + + { + // Take references explicitly so that we can hold multiple references to self. + let pending_inbound_htlcs: &mut Vec<_> = &mut self.pending_inbound_htlcs; + let pending_outbound_htlcs: &mut Vec<_> = &mut self.pending_outbound_htlcs; + let logger = LogHolder { logger: &self.logger }; + + // We really shouldnt have two passes here, but retain gives a non-mutable ref (Rust bug) + pending_inbound_htlcs.retain(|htlc| { + if let &InboundHTLCState::LocalRemoved(ref reason) = &htlc.state { + log_trace!(logger, " ...removing inbound LocalRemoved {}", log_bytes!(htlc.payment_hash.0)); + if let &InboundHTLCRemovalReason::Fulfill(_) = reason { + value_to_self_msat_diff += htlc.amount_msat as i64; + } + false + } else { true } + }); + pending_outbound_htlcs.retain(|htlc| { + if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) = &htlc.state { + log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", log_bytes!(htlc.payment_hash.0)); + if let Some(reason) = fail_reason.clone() { // We really want take() here, but, again, non-mut ref :( + revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason)); + } else { + // They fulfilled, so we sent them money + value_to_self_msat_diff -= htlc.amount_msat as i64; + } + false + } else { true } + }); + for htlc in pending_inbound_htlcs.iter_mut() { + let swap = if let &InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) = &htlc.state { + log_trace!(logger, " ...promoting inbound AwaitingRemoteRevokeToAnnounce {} to Committed", log_bytes!(htlc.payment_hash.0)); + true + } else if let &InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) = &htlc.state { + log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", log_bytes!(htlc.payment_hash.0)); + true + } else { false }; + if swap { + let mut state = InboundHTLCState::Committed; + mem::swap(&mut state, &mut htlc.state); + + if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info) = state { + htlc.state = InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info); + require_commitment = true; + } else if let InboundHTLCState::AwaitingAnnouncedRemoteRevoke(forward_info) = state { + match forward_info { + PendingHTLCStatus::Fail(fail_msg) => { + require_commitment = true; + match fail_msg { + HTLCFailureMsg::Relay(msg) => { + htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(msg.reason.clone())); + update_fail_htlcs.push(msg) + }, + HTLCFailureMsg::Malformed(msg) => { + htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed((msg.sha256_of_onion, msg.failure_code))); + update_fail_malformed_htlcs.push(msg) + }, + } + }, + PendingHTLCStatus::Forward(forward_info) => { + to_forward_infos.push((forward_info, htlc.htlc_id)); + htlc.state = InboundHTLCState::Committed; } - }, - PendingHTLCStatus::Forward(forward_info) => { - to_forward_infos.push((forward_info, htlc.htlc_id)); - htlc.state = InboundHTLCState::Committed; } } } } - } - for htlc in self.pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { - htlc.state = OutboundHTLCState::Committed; - } else if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state { - htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke; - require_commitment = true; + for htlc in pending_outbound_htlcs.iter_mut() { + if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { + log_trace!(logger, " ...promoting outbound LocalAnnounced {} to Committed", log_bytes!(htlc.payment_hash.0)); + htlc.state = OutboundHTLCState::Committed; + } + if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.state { + Some(fail_reason.take()) + } else { None } { + log_trace!(logger, " ...promoting outbound AwaitingRemoteRevokeToRemove {} to AwaitingRemovedRemoteRevoke", log_bytes!(htlc.payment_hash.0)); + htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason); + require_commitment = true; + } } } self.value_to_self_msat = (self.value_to_self_msat as i64 + value_to_self_msat_diff) as u64; @@ -2213,7 +2233,7 @@ impl Channel { self.next_remote_htlc_id -= inbound_drop_count; for htlc in self.pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::RemoteRemoved = htlc.state { + if let OutboundHTLCState::RemoteRemoved(_) = htlc.state { // They sent us an update to remove this but haven't yet sent the corresponding // commitment_signed, we need to move it back to Committed and they can re-send // the update upon reconnection. @@ -2356,6 +2376,8 @@ impl Channel { } } + log_trace!(self, "Regenerated latest commitment update with {} update_adds, {} update_fulfills, {} update_fails, and {} update_fail_malformeds", + update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len(), update_fail_malformed_htlcs.len()); msgs::CommitmentUpdate { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, update_fee: None, //TODO: We need to support re-generating any update_fees in the last commitment_signed! @@ -3124,7 +3146,7 @@ impl Channel { excess_data: Vec::new(), }; - let msghash = hash_to_message!(&Sha256dHash::from_data(&msg.encode()[..])[..]); + let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]); let sig = self.secp_ctx.sign(&msghash, &self.local_keys.funding_key); Ok((msg, sig)) @@ -3229,7 +3251,6 @@ impl Channel { cltv_expiry: cltv_expiry, state: OutboundHTLCState::LocalAnnounced(Box::new(onion_routing_packet.clone())), source, - fail_reason: None, }); let res = msgs::UpdateAddHTLC { @@ -3294,8 +3315,10 @@ impl Channel { } } for htlc in self.pending_outbound_htlcs.iter_mut() { - if let OutboundHTLCState::AwaitingRemoteRevokeToRemove = htlc.state { - htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke; + if let Some(fail_reason) = if let &mut OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref mut fail_reason) = &mut htlc.state { + Some(fail_reason.take()) + } else { None } { + htlc.state = OutboundHTLCState::AwaitingRemovedRemoteRevoke(fail_reason); } } @@ -3561,7 +3584,6 @@ impl Writeable for Channel { htlc.cltv_expiry.write(writer)?; htlc.payment_hash.write(writer)?; htlc.source.write(writer)?; - write_option!(htlc.fail_reason); match &htlc.state { &OutboundHTLCState::LocalAnnounced(ref onion_packet) => { 0u8.write(writer)?; @@ -3570,14 +3592,17 @@ impl Writeable for Channel { &OutboundHTLCState::Committed => { 1u8.write(writer)?; }, - &OutboundHTLCState::RemoteRemoved => { + &OutboundHTLCState::RemoteRemoved(ref fail_reason) => { 2u8.write(writer)?; + write_option!(*fail_reason); }, - &OutboundHTLCState::AwaitingRemoteRevokeToRemove => { + &OutboundHTLCState::AwaitingRemoteRevokeToRemove(ref fail_reason) => { 3u8.write(writer)?; + write_option!(*fail_reason); }, - &OutboundHTLCState::AwaitingRemovedRemoteRevoke => { + &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref fail_reason) => { 4u8.write(writer)?; + write_option!(*fail_reason); }, } } @@ -3740,13 +3765,12 @@ impl ReadableArgs> for Channel { cltv_expiry: Readable::read(reader)?, payment_hash: Readable::read(reader)?, source: Readable::read(reader)?, - fail_reason: Readable::read(reader)?, state: match >::read(reader)? { 0 => OutboundHTLCState::LocalAnnounced(Box::new(Readable::read(reader)?)), 1 => OutboundHTLCState::Committed, - 2 => OutboundHTLCState::RemoteRemoved, - 3 => OutboundHTLCState::AwaitingRemoteRevokeToRemove, - 4 => OutboundHTLCState::AwaitingRemovedRemoteRevoke, + 2 => OutboundHTLCState::RemoteRemoved(Readable::read(reader)?), + 3 => OutboundHTLCState::AwaitingRemoteRevokeToRemove(Readable::read(reader)?), + 4 => OutboundHTLCState::AwaitingRemovedRemoteRevoke(Readable::read(reader)?), _ => return Err(DecodeError::InvalidValue), }, }); @@ -3935,12 +3959,12 @@ impl ReadableArgs> for Channel { #[cfg(test)] mod tests { - use bitcoin::util::hash::{Sha256dHash, Hash160}; use bitcoin::util::bip143; use bitcoin::consensus::encode::serialize; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::opcodes; + use bitcoin_hashes::hex::FromHex; use hex; use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys}; @@ -3955,6 +3979,8 @@ mod tests { use secp256k1::{Secp256k1,Message,Signature}; use secp256k1::key::{SecretKey,PublicKey}; use bitcoin_hashes::sha256::Hash as Sha256; + use bitcoin_hashes::sha256d::Hash as Sha256dHash; + use bitcoin_hashes::hash160::Hash as Hash160; use bitcoin_hashes::Hash; use std::sync::Arc; @@ -3981,7 +4007,7 @@ mod tests { fn get_destination_script(&self) -> Script { let secp_ctx = Secp256k1::signing_only(); let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); - let our_channel_monitor_claim_key_hash = Hash160::from_data(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); + let our_channel_monitor_claim_key_hash = Hash160::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() } @@ -4139,7 +4165,6 @@ mod tests { payment_hash: PaymentHash([0; 32]), state: OutboundHTLCState::Committed, source: HTLCSource::dummy(), - fail_reason: None, }; out.payment_hash.0 = Sha256::hash(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).into_inner(); out @@ -4152,7 +4177,6 @@ mod tests { payment_hash: PaymentHash([0; 32]), state: OutboundHTLCState::Committed, source: HTLCSource::dummy(), - fail_reason: None, }; out.payment_hash.0 = Sha256::hash(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).into_inner(); out