diff --git a/fuzz/fuzz_targets/full_stack_target.rs b/fuzz/fuzz_targets/full_stack_target.rs index 0524f578e45..a68970cc6e6 100644 --- a/fuzz/fuzz_targets/full_stack_target.rs +++ b/fuzz/fuzz_targets/full_stack_target.rs @@ -17,7 +17,7 @@ use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,C use lightning::chain::transaction::OutPoint; use lightning::chain::keysinterface::{ChannelKeys, KeysInterface}; use lightning::ln::channelmonitor; -use lightning::ln::channelmanager::{ChannelManager, PaymentFailReason}; +use lightning::ln::channelmanager::{ChannelManager, PaymentFailReason, PaymentHash, PaymentPreimage}; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; use lightning::ln::router::Router; use lightning::util::events::{EventsProvider,Event}; @@ -328,7 +328,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { }, our_network_key, Arc::clone(&logger))); let mut should_forward = false; - let mut payments_received: Vec<[u8; 32]> = Vec::new(); + let mut payments_received: Vec = Vec::new(); let mut payments_sent = 0; let mut pending_funding_generation: Vec<([u8; 32], u64, Script)> = Vec::new(); let mut pending_funding_signatures = HashMap::new(); @@ -380,11 +380,11 @@ pub fn do_test(data: &[u8], logger: &Arc) { Ok(route) => route, Err(_) => return, }; - let mut payment_hash = [0; 32]; - payment_hash[0..8].copy_from_slice(&be64_to_array(payments_sent)); + let mut payment_hash = PaymentHash([0; 32]); + payment_hash.0[0..8].copy_from_slice(&be64_to_array(payments_sent)); let mut sha = Sha256::new(); - sha.input(&payment_hash); - sha.result(&mut payment_hash); + sha.input(&payment_hash.0[..]); + sha.result(&mut payment_hash.0[..]); payments_sent += 1; match channelmanager.send_payment(route, payment_hash) { Ok(_) => {}, @@ -418,11 +418,11 @@ pub fn do_test(data: &[u8], logger: &Arc) { // for the remaining bytes. Thus, if not all remaining bytes are 0s we cannot // fulfill this HTLC, but if they are, we can just take the first byte and // place that anywhere in our preimage. - if &payment[1..] != &[0; 31] { + if &payment.0[1..] != &[0; 31] { channelmanager.fail_htlc_backwards(&payment, PaymentFailReason::PreimageUnknown); } else { - let mut payment_preimage = [0; 32]; - payment_preimage[0] = payment[0]; + let mut payment_preimage = PaymentPreimage([0; 32]); + payment_preimage.0[0] = payment.0[0]; channelmanager.claim_funds(payment_preimage); } } diff --git a/src/ln/chan_utils.rs b/src/ln/chan_utils.rs index 7f259d98149..dbd6bdccc27 100644 --- a/src/ln/chan_utils.rs +++ b/src/ln/chan_utils.rs @@ -3,6 +3,8 @@ use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{TxIn,TxOut,OutPoint,Transaction}; use bitcoin::util::hash::{Hash160,Sha256dHash}; +use ln::channelmanager::PaymentHash; + use secp256k1::key::{PublicKey,SecretKey}; use secp256k1::Secp256k1; use secp256k1; @@ -156,7 +158,7 @@ pub struct HTLCOutputInCommitment { pub offered: bool, pub amount_msat: u64, pub cltv_expiry: u32, - pub payment_hash: [u8; 32], + pub payment_hash: PaymentHash, pub transaction_output_index: u32, } @@ -164,7 +166,7 @@ pub struct HTLCOutputInCommitment { pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a_htlc_key: &PublicKey, b_htlc_key: &PublicKey, revocation_key: &PublicKey) -> Script { let payment_hash160 = { let mut ripemd = Ripemd160::new(); - ripemd.input(&htlc.payment_hash); + ripemd.input(&htlc.payment_hash.0[..]); let mut res = [0; 20]; ripemd.result(&mut res); res diff --git a/src/ln/channel.rs b/src/ln/channel.rs index 296d97c164e..5405a69a402 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -15,7 +15,7 @@ use crypto::digest::Digest; use ln::msgs; use ln::msgs::DecodeError; use ln::channelmonitor::ChannelMonitor; -use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder}; +use ln::channelmanager::{PendingHTLCStatus, HTLCSource, HTLCFailReason, HTLCFailureMsg, PendingForwardHTLCInfo, RAACommitmentOrder, PaymentPreimage, PaymentHash}; use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; @@ -48,7 +48,7 @@ pub struct ChannelValueStat { enum InboundHTLCRemovalReason { FailRelay(msgs::OnionErrorPacket), FailMalformed(([u8; 32], u16)), - Fulfill([u8; 32]), + Fulfill(PaymentPreimage), } enum InboundHTLCState { @@ -84,7 +84,7 @@ struct InboundHTLCOutput { htlc_id: u64, amount_msat: u64, cltv_expiry: u32, - payment_hash: [u8; 32], + payment_hash: PaymentHash, state: InboundHTLCState, } @@ -124,7 +124,7 @@ struct OutboundHTLCOutput { htlc_id: u64, amount_msat: u64, cltv_expiry: u32, - payment_hash: [u8; 32], + payment_hash: PaymentHash, state: OutboundHTLCState, source: HTLCSource, /// If we're in a removed state, set if they failed, otherwise None @@ -149,13 +149,13 @@ enum HTLCUpdateAwaitingACK { // always outbound amount_msat: u64, cltv_expiry: u32, - payment_hash: [u8; 32], + payment_hash: PaymentHash, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, time_created: Instant, //TODO: Some kind of timeout thing-a-majig }, ClaimHTLC { - payment_preimage: [u8; 32], + payment_preimage: PaymentPreimage, htlc_id: u64, }, FailHTLC { @@ -263,7 +263,7 @@ pub(super) struct Channel { monitor_pending_commitment_signed: bool, monitor_pending_order: Option, monitor_pending_forwards: Vec<(PendingForwardHTLCInfo, u64)>, - monitor_pending_failures: Vec<(HTLCSource, [u8; 32], HTLCFailReason)>, + monitor_pending_failures: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, // pending_update_fee is filled when sending and receiving update_fee // For outbound channel, feerate_per_kw is updated with the value from @@ -364,6 +364,12 @@ const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: /// it's 2^24. pub const MAX_FUNDING_SATOSHIS: u64 = (1 << 24); +#[cfg(test)] +pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 138; //Here we have a diff due to HTLC CLTV expiry being < 2^15 in test +#[cfg(not(test))] +pub const ACCEPTED_HTLC_SCRIPT_WEIGHT: usize = 139; +pub const OFFERED_HTLC_SCRIPT_WEIGHT: usize = 133; + /// Used to return a simple Error back to ChannelManager. Will get converted to a /// msgs::ErrorAction::SendErrorMessage or msgs::ErrorAction::IgnoreError as appropriate with our /// channel_id in ChannelManager. @@ -751,7 +757,7 @@ impl Channel { /// generated by the peer which proposed adding the HTLCs, and thus we need to understand both /// which peer generated this transaction and "to whom" this transaction flows. #[inline] - fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec) { + fn build_commitment_transaction(&self, commitment_number: u64, keys: &TxCreationKeys, local: bool, generated_by_local: bool, feerate_per_kw: u64) -> (Transaction, Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)>) { let obscured_commitment_transaction_number = self.get_commitment_transaction_number_obscure_factor() ^ (INITIAL_COMMITMENT_NUMBER - commitment_number); let txins = { @@ -765,7 +771,7 @@ impl Channel { ins }; - let mut txouts: Vec<(TxOut, Option)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2); + let mut txouts: Vec<(TxOut, Option<(HTLCOutputInCommitment, Option<&HTLCSource>)>)> = Vec::with_capacity(self.pending_inbound_htlcs.len() + self.pending_outbound_htlcs.len() + 2); let dust_limit_satoshis = if local { self.our_dust_limit_satoshis } else { self.their_dust_limit_satoshis }; let mut remote_htlc_total_msat = 0; @@ -773,14 +779,14 @@ impl Channel { let mut value_to_self_msat_offset = 0; macro_rules! add_htlc_output { - ($htlc: expr, $outbound: expr) => { + ($htlc: expr, $outbound: expr, $source: expr) => { if $outbound == local { // "offered HTLC output" if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000) { let htlc_in_tx = get_htlc_in_commitment!($htlc, true); txouts.push((TxOut { script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(), value: $htlc.amount_msat / 1000 - }, Some(htlc_in_tx))); + }, Some((htlc_in_tx, $source)))); } } else { if $htlc.amount_msat / 1000 >= dust_limit_satoshis + (feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000) { @@ -788,7 +794,7 @@ impl Channel { txouts.push((TxOut { // "received HTLC output" script_pubkey: chan_utils::get_htlc_redeemscript(&htlc_in_tx, &keys).to_v0_p2wsh(), value: $htlc.amount_msat / 1000 - }, Some(htlc_in_tx))); + }, Some((htlc_in_tx, $source)))); } } } @@ -804,7 +810,7 @@ impl Channel { }; if include { - add_htlc_output!(htlc, false); + add_htlc_output!(htlc, false, None); remote_htlc_total_msat += htlc.amount_msat; } else { match &htlc.state { @@ -830,7 +836,7 @@ impl Channel { }; if include { - add_htlc_output!(htlc, true); + add_htlc_output!(htlc, true, Some(&htlc.source)); local_htlc_total_msat += htlc.amount_msat; } else { match htlc.state { @@ -901,12 +907,12 @@ impl Channel { transaction_utils::sort_outputs(&mut txouts); let mut outputs: Vec = Vec::with_capacity(txouts.len()); - let mut htlcs_used: Vec = Vec::with_capacity(txouts.len()); + let mut htlcs_used: Vec<(HTLCOutputInCommitment, Option<&HTLCSource>)> = Vec::with_capacity(txouts.len()); for (idx, out) in txouts.drain(..).enumerate() { outputs.push(out.0); - if let Some(out_htlc) = out.1 { - htlcs_used.push(out_htlc); - htlcs_used.last_mut().unwrap().transaction_output_index = idx as u32; + if let Some(mut out_htlc) = out.1 { + out_htlc.0.transaction_output_index = idx as u32; + htlcs_used.push((out_htlc.0, out_htlc.1)); } } @@ -1085,7 +1091,7 @@ impl Channel { /// Signs a transaction created by build_htlc_transaction. If the transaction is an /// HTLC-Success transaction (ie htlc.offered is false), preimate must be set! - fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<[u8; 32]>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result { + fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result { if tx.input.len() != 1 { panic!("Tried to sign HTLC transaction that had input count != 1!"); } @@ -1110,7 +1116,7 @@ impl Channel { if htlc.offered { tx.input[0].witness.push(Vec::new()); } else { - tx.input[0].witness.push(preimage.unwrap().to_vec()); + tx.input[0].witness.push(preimage.unwrap().0.to_vec()); } tx.input[0].witness.push(htlc_redeemscript.into_bytes()); @@ -1121,7 +1127,7 @@ impl Channel { /// Per HTLC, only one get_update_fail_htlc or get_update_fulfill_htlc call may be made. /// In such cases we debug_assert!(false) and return an IgnoreError. Thus, will always return /// Ok(_) if debug assertions are turned on and preconditions are met. - fn get_update_fulfill_htlc(&mut self, htlc_id_arg: u64, payment_preimage_arg: [u8; 32]) -> Result<(Option, Option), ChannelError> { + fn get_update_fulfill_htlc(&mut self, htlc_id_arg: u64, payment_preimage_arg: PaymentPreimage) -> Result<(Option, Option), ChannelError> { // Either ChannelFunded got set (which means it wont bet unset) or there is no way any // caller thought we could have something claimed (cause we wouldn't have accepted in an // incoming HTLC anyway). If we got to ShutdownComplete, callers aren't allowed to call us, @@ -1132,18 +1138,30 @@ impl Channel { assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); let mut sha = Sha256::new(); - sha.input(&payment_preimage_arg); - let mut payment_hash_calc = [0; 32]; - sha.result(&mut payment_hash_calc); + sha.input(&payment_preimage_arg.0[..]); + let mut payment_hash_calc = PaymentHash([0; 32]); + sha.result(&mut payment_hash_calc.0[..]); let mut pending_idx = std::usize::MAX; for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() { if htlc.htlc_id == htlc_id_arg { assert_eq!(htlc.payment_hash, payment_hash_calc); - if let InboundHTLCState::Committed = htlc.state { - } else { - debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); - // Don't return in release mode here so that we can update channel_monitor + match htlc.state { + InboundHTLCState::Committed => {}, + InboundHTLCState::LocalRemoved(ref reason) => { + // ChannelManager may generate duplicate claims due to HTLC update events from on-chain + // ChannelsMonitors during block rescan + // TODO: Ideally we'd just drop these + if let &InboundHTLCRemovalReason::Fulfill(_) = reason { + return Ok((None, None)); + } else { + assert!(false, "Got an update_fulfill for previously-failed HTLC!"); + } + }, + _ => { + debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); + // Don't return in release mode here so that we can update channel_monitor + } } pending_idx = idx; break; @@ -1203,7 +1221,7 @@ impl Channel { }), Some(self.channel_monitor.clone()))) } - pub fn get_update_fulfill_htlc_and_commit(&mut self, htlc_id: u64, payment_preimage: [u8; 32]) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option), ChannelError> { + pub fn get_update_fulfill_htlc_and_commit(&mut self, htlc_id: u64, payment_preimage: PaymentPreimage) -> Result<(Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)>, Option), ChannelError> { match self.get_update_fulfill_htlc(htlc_id, payment_preimage)? { (Some(update_fulfill_htlc), _) => { let (commitment, monitor_update) = self.send_commitment_no_status_check()?; @@ -1226,10 +1244,22 @@ impl Channel { let mut pending_idx = std::usize::MAX; for (idx, htlc) in self.pending_inbound_htlcs.iter().enumerate() { if htlc.htlc_id == htlc_id_arg { - if let InboundHTLCState::Committed = htlc.state { - } else { - debug_assert!(false, "Have an inbound HTLC we tried to fail before it was fully committed to"); - return Err(ChannelError::Ignore("Unable to find a pending HTLC which matched the given HTLC ID")); + match htlc.state { + InboundHTLCState::Committed => {}, + InboundHTLCState::LocalRemoved(ref reason) => { + // ChannelManager may generate duplicate claims due to HTLC update events from on-chain + // ChannelsMonitors during block rescan + // TODO: Ideally we'd just drop these + if let &InboundHTLCRemovalReason::Fulfill(_) = reason { + assert!(false, "Got an update_fail for previously-fulfilled HTLC!"); + } else { + return Ok(None); + } + }, + _ => { + debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to"); + return Err(ChannelError::Ignore("Unable to find a pending HTLC which matchd the given HTLC ID")); + } } pending_idx = idx; } @@ -1579,7 +1609,7 @@ impl Channel { /// Marks an outbound HTLC which we have received update_fail/fulfill/malformed #[inline] - fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option) -> Result<&HTLCSource, ChannelError> { + fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option, fail_reason: Option) -> Result<&HTLCSource, ChannelError> { for htlc in self.pending_outbound_htlcs.iter_mut() { if htlc.htlc_id == htlc_id { match check_preimage { @@ -1614,9 +1644,9 @@ impl Channel { } let mut sha = Sha256::new(); - sha.input(&msg.payment_preimage); - let mut payment_hash = [0; 32]; - sha.result(&mut payment_hash); + sha.input(&msg.payment_preimage.0[..]); + let mut payment_hash = PaymentHash([0; 32]); + sha.result(&mut payment_hash.0[..]); self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None).map(|source| source.clone()) } @@ -1668,7 +1698,11 @@ impl Channel { self.feerate_per_kw }; - let mut local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw); + let mut local_commitment_tx = { + let mut commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false, feerate_per_kw); + let htlcs_cloned: Vec<_> = commitment_tx.1.drain(..).map(|htlc_pair| (htlc_pair.0, htlc_pair.1.map(|source| (*source).clone()))).collect(); + (commitment_tx.0, htlcs_cloned) + }; let local_commitment_txid = local_commitment_tx.0.txid(); let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_commitment_tx.0).sighash_all(&local_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap(); secp_check!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey.unwrap()), "Invalid commitment tx signature from peer"); @@ -1692,19 +1726,19 @@ impl Channel { new_local_commitment_txn.push(local_commitment_tx.0.clone()); let mut htlcs_and_sigs = Vec::with_capacity(local_commitment_tx.1.len()); - for (idx, ref htlc) in local_commitment_tx.1.iter().enumerate() { - let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys, feerate_per_kw); + for (idx, (htlc, htlc_source)) in local_commitment_tx.1.drain(..).enumerate() { + let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, &htlc, true, &local_keys, feerate_per_kw); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &local_keys); let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap(); secp_check!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx signature from peer"); let htlc_sig = if htlc.offered { - let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, htlc, &local_keys)?; + let htlc_sig = self.sign_htlc_transaction(&mut htlc_tx, &msg.htlc_signatures[idx], &None, &htlc, &local_keys)?; new_local_commitment_txn.push(htlc_tx); htlc_sig } else { - self.create_htlc_tx_signature(&htlc_tx, htlc, &local_keys)?.1 + self.create_htlc_tx_signature(&htlc_tx, &htlc, &local_keys)?.1 }; - htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig)); + htlcs_and_sigs.push((htlc, msg.htlc_signatures[idx], htlc_sig, htlc_source)); } let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1)); @@ -1797,16 +1831,16 @@ impl Channel { self.holding_cell_htlc_updates.push(htlc_update); } else { match &htlc_update { - &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, payment_hash, ref source, ref onion_routing_packet, ..} => { - match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone()) { + &HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => { + match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone()) { Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()), Err(e) => { err = Some(e); } } }, - &HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, htlc_id, .. } => { - match self.get_update_fulfill_htlc(htlc_id, payment_preimage) { + &HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, htlc_id, .. } => { + match self.get_update_fulfill_htlc(htlc_id, *payment_preimage) { Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.0.unwrap()), Err(e) => { if let ChannelError::Ignore(_) = e {} @@ -1874,7 +1908,7 @@ impl Channel { /// waiting on this revoke_and_ack. The generation of this new commitment_signed may also fail, /// generating an appropriate error *after* the channel state has been updated based on the /// revoke_and_ack message. - pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK, fee_estimator: &FeeEstimator) -> Result<(Option, Vec<(PendingForwardHTLCInfo, u64)>, Vec<(HTLCSource, [u8; 32], HTLCFailReason)>, Option, ChannelMonitor), ChannelError> { + pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK, fee_estimator: &FeeEstimator) -> Result<(Option, Vec<(PendingForwardHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>, Option, ChannelMonitor), ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Close("Got revoke/ACK message when channel was not in an operational state")); } @@ -2084,7 +2118,7 @@ impl Channel { /// implicitly dropping) and the payment_hashes of HTLCs we tried to add but are dropping. /// No further message handling calls may be made until a channel_reestablish dance has /// completed. - pub fn remove_uncommitted_htlcs_and_mark_paused(&mut self) -> Vec<(HTLCSource, [u8; 32])> { + pub fn remove_uncommitted_htlcs_and_mark_paused(&mut self) -> Vec<(HTLCSource, PaymentHash)> { let mut outbound_drops = Vec::new(); assert_eq!(self.channel_state & ChannelState::ShutdownComplete as u32, 0); @@ -2173,7 +2207,7 @@ impl Channel { /// Indicates that the latest ChannelMonitor update has been committed by the client /// successfully and we should restore normal operation. Returns messages which should be sent /// to the remote side. - pub fn monitor_updating_restored(&mut self) -> (Option, Option, RAACommitmentOrder, Vec<(PendingForwardHTLCInfo, u64)>, Vec<(HTLCSource, [u8; 32], HTLCFailReason)>) { + pub fn monitor_updating_restored(&mut self) -> (Option, Option, RAACommitmentOrder, Vec<(PendingForwardHTLCInfo, u64)>, Vec<(HTLCSource, PaymentHash, HTLCFailReason)>) { assert_eq!(self.channel_state & ChannelState::MonitorUpdateFailed as u32, ChannelState::MonitorUpdateFailed as u32); self.channel_state &= !(ChannelState::MonitorUpdateFailed as u32); @@ -2430,7 +2464,7 @@ impl Channel { }) } - pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option, Option, Vec<(HTLCSource, [u8; 32])>), ChannelError> { + pub fn shutdown(&mut self, fee_estimator: &FeeEstimator, msg: &msgs::Shutdown) -> Result<(Option, Option, Vec<(HTLCSource, PaymentHash)>), ChannelError> { if self.channel_state & (ChannelState::PeerDisconnected as u32) == ChannelState::PeerDisconnected as u32 { return Err(ChannelError::Close("Peer sent shutdown when we needed a channel_reestablish")); } @@ -2852,8 +2886,8 @@ impl Channel { } self.funding_tx_confirmations = 1; self.short_channel_id = Some(((height as u64) << (5*8)) | - ((*index_in_block as u64) << (2*8)) | - ((txo_idx as u64) << (0*8))); + ((*index_in_block as u64) << (2*8)) | + ((txo_idx as u64) << (0*8))); } } } @@ -3088,7 +3122,7 @@ impl Channel { /// waiting on the remote peer to send us a revoke_and_ack during which time we cannot add new /// HTLCs on the wire or we wouldn't be able to determine what they actually ACK'ed. /// You MUST call send_commitment prior to any other calls on this Channel - pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result, ChannelError> { + pub fn send_htlc(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result, ChannelError> { if (self.channel_state & (ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelFunded as u32) { return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down")); } @@ -3236,7 +3270,7 @@ impl Channel { /// Only fails in case of bad keys. Used for channel_reestablish commitment_signed generation /// when we shouldn't change HTLC/channel state. - fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec)), ChannelError> { + fn send_commitment_no_state_update(&self) -> Result<(msgs::CommitmentSigned, (Transaction, Vec<(HTLCOutputInCommitment, Option)>)), ChannelError> { let funding_script = self.get_funding_redeemscript(); let mut feerate_per_kw = self.feerate_per_kw; @@ -3247,14 +3281,14 @@ impl Channel { } let remote_keys = self.build_remote_transaction_keys()?; - let remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true, feerate_per_kw); + let mut remote_commitment_tx = self.build_commitment_transaction(self.cur_remote_commitment_transaction_number, &remote_keys, false, true, feerate_per_kw); let remote_commitment_txid = remote_commitment_tx.0.txid(); let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_commitment_tx.0).sighash_all(&remote_commitment_tx.0.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap(); let our_sig = self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key); let mut htlc_sigs = Vec::new(); - for ref htlc in remote_commitment_tx.1.iter() { + for &(ref htlc, _) in remote_commitment_tx.1.iter() { let htlc_tx = self.build_htlc_transaction(&remote_commitment_txid, htlc, false, &remote_keys, feerate_per_kw); let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &remote_keys); let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap(); @@ -3262,18 +3296,19 @@ impl Channel { htlc_sigs.push(self.secp_ctx.sign(&htlc_sighash, &our_htlc_key)); } + let htlcs_no_ref = remote_commitment_tx.1.drain(..).map(|htlc_pair| (htlc_pair.0, htlc_pair.1.map(|source| source.clone()))).collect(); Ok((msgs::CommitmentSigned { channel_id: self.channel_id, signature: our_sig, htlc_signatures: htlc_sigs, - }, remote_commitment_tx)) + }, (remote_commitment_tx.0, htlcs_no_ref))) } /// Adds a pending outbound HTLC to this channel, and creates a signed commitment transaction /// to send to the remote peer in one go. /// Shorthand for calling send_htlc() followed by send_commitment(), see docs on those for /// more info. - pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result, ChannelError> { + pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket) -> Result, ChannelError> { match self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet)? { Some(update_add_htlc) => { let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?; @@ -3285,7 +3320,7 @@ impl Channel { /// Begins the shutdown process, getting a message for the remote peer and returning all /// holding cell HTLCs for payment failure. - pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, [u8; 32])>), APIError> { + pub fn get_shutdown(&mut self) -> Result<(msgs::Shutdown, Vec<(HTLCSource, PaymentHash)>), APIError> { for htlc in self.pending_outbound_htlcs.iter() { if let OutboundHTLCState::LocalAnnounced(_) = htlc.state { return Err(APIError::APIMisuseError{err: "Cannot begin shutdown with pending HTLCs. Process pending events first"}); @@ -3339,7 +3374,7 @@ impl Channel { /// those explicitly stated to be allowed after shutdown completes, eg some simple getters). /// Also returns the list of payment_hashes for channels which we can safely fail backwards /// immediately (others we will have to allow to time out). - pub fn force_shutdown(&mut self) -> (Vec, Vec<(HTLCSource, [u8; 32])>) { + pub fn force_shutdown(&mut self) -> (Vec, Vec<(HTLCSource, PaymentHash)>) { assert!(self.channel_state != ChannelState::ShutdownComplete as u32); // We go ahead and "free" any holding cell HTLCs or HTLCs we haven't yet committed to and @@ -3868,7 +3903,7 @@ mod tests { use bitcoin::blockdata::transaction::Transaction; use bitcoin::blockdata::opcodes; use hex; - use ln::channelmanager::HTLCSource; + use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; use ln::channel::{Channel,ChannelKeys,InboundHTLCOutput,OutboundHTLCOutput,InboundHTLCState,OutboundHTLCState,HTLCOutputInCommitment,TxCreationKeys}; use ln::channel::MAX_FUNDING_SATOSHIS; use ln::chan_utils; @@ -3979,7 +4014,11 @@ mod tests { macro_rules! test_commitment { ( $their_sig_hex: expr, $our_sig_hex: expr, $tx_hex: expr) => { - unsigned_tx = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw); + unsigned_tx = { + let mut tx = chan.build_commitment_transaction(0xffffffffffff - 42, &keys, true, false, chan.feerate_per_kw); + let htlcs = tx.1.drain(..).map(|htlc_pair| htlc_pair.0).collect(); + (tx.0, htlcs) + }; let their_signature = Signature::from_der(&secp_ctx, &hex::decode($their_sig_hex).unwrap()[..]).unwrap(); let sighash = Message::from_slice(&bip143::SighashComponents::new(&unsigned_tx.0).sighash_all(&unsigned_tx.0.input[0], &chan.get_funding_redeemscript(), chan.channel_value_satoshis)[..]).unwrap(); secp_ctx.verify(&sighash, &their_signature, &chan.their_funding_pubkey.unwrap()).unwrap(); @@ -4001,17 +4040,17 @@ mod tests { let htlc_sighash = Message::from_slice(&bip143::SighashComponents::new(&htlc_tx).sighash_all(&htlc_tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap(); secp_ctx.verify(&htlc_sighash, &remote_signature, &keys.b_htlc_key).unwrap(); - let mut preimage: Option<[u8; 32]> = None; + let mut preimage: Option = None; if !htlc.offered { for i in 0..5 { let mut sha = Sha256::new(); sha.input(&[i; 32]); - let mut out = [0; 32]; - sha.result(&mut out); + let mut out = PaymentHash([0; 32]); + sha.result(&mut out.0[..]); if out == htlc.payment_hash { - preimage = Some([i; 32]); + preimage = Some(PaymentPreimage([i; 32])); } } @@ -4038,12 +4077,12 @@ mod tests { htlc_id: 0, amount_msat: 1000000, cltv_expiry: 500, - payment_hash: [0; 32], + payment_hash: PaymentHash([0; 32]), state: InboundHTLCState::Committed, }; let mut sha = Sha256::new(); sha.input(&hex::decode("0000000000000000000000000000000000000000000000000000000000000000").unwrap()); - sha.result(&mut out.payment_hash); + sha.result(&mut out.payment_hash.0[..]); out }); chan.pending_inbound_htlcs.push({ @@ -4051,12 +4090,12 @@ mod tests { htlc_id: 1, amount_msat: 2000000, cltv_expiry: 501, - payment_hash: [0; 32], + payment_hash: PaymentHash([0; 32]), state: InboundHTLCState::Committed, }; let mut sha = Sha256::new(); sha.input(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()); - sha.result(&mut out.payment_hash); + sha.result(&mut out.payment_hash.0[..]); out }); chan.pending_outbound_htlcs.push({ @@ -4064,14 +4103,14 @@ mod tests { htlc_id: 2, amount_msat: 2000000, cltv_expiry: 502, - payment_hash: [0; 32], + payment_hash: PaymentHash([0; 32]), state: OutboundHTLCState::Committed, source: HTLCSource::dummy(), fail_reason: None, }; let mut sha = Sha256::new(); sha.input(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()); - sha.result(&mut out.payment_hash); + sha.result(&mut out.payment_hash.0[..]); out }); chan.pending_outbound_htlcs.push({ @@ -4079,14 +4118,14 @@ mod tests { htlc_id: 3, amount_msat: 3000000, cltv_expiry: 503, - payment_hash: [0; 32], + payment_hash: PaymentHash([0; 32]), state: OutboundHTLCState::Committed, source: HTLCSource::dummy(), fail_reason: None, }; let mut sha = Sha256::new(); sha.input(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()); - sha.result(&mut out.payment_hash); + sha.result(&mut out.payment_hash.0[..]); out }); chan.pending_inbound_htlcs.push({ @@ -4094,12 +4133,12 @@ mod tests { htlc_id: 4, amount_msat: 4000000, cltv_expiry: 504, - payment_hash: [0; 32], + payment_hash: PaymentHash([0; 32]), state: InboundHTLCState::Committed, }; let mut sha = Sha256::new(); sha.input(&hex::decode("0404040404040404040404040404040404040404040404040404040404040404").unwrap()); - sha.result(&mut out.payment_hash); + sha.result(&mut out.payment_hash.0[..]); out }); diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index a4723646971..52948173dfd 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -63,6 +63,7 @@ use std::time::{Instant,Duration}; mod channel_held_info { use ln::msgs; use ln::router::Route; + use ln::channelmanager::PaymentHash; use secp256k1::key::SecretKey; /// Stores the info we will need to send when we want to forward an HTLC onwards @@ -70,7 +71,7 @@ mod channel_held_info { pub struct PendingForwardHTLCInfo { pub(super) onion_packet: Option, pub(super) incoming_shared_secret: [u8; 32], - pub(super) payment_hash: [u8; 32], + pub(super) payment_hash: PaymentHash, pub(super) short_channel_id: u64, pub(super) amt_to_forward: u64, pub(super) outgoing_cltv_value: u32, @@ -90,15 +91,15 @@ mod channel_held_info { } /// Tracks the inbound corresponding to an outbound HTLC - #[derive(Clone)] + #[derive(Clone, PartialEq)] pub struct HTLCPreviousHopData { - pub(super) short_channel_id: u64, + pub(crate) short_channel_id: u64, pub(super) htlc_id: u64, pub(super) incoming_packet_shared_secret: [u8; 32], } /// Tracks the inbound corresponding to an outbound HTLC - #[derive(Clone)] + #[derive(Clone, PartialEq)] pub enum HTLCSource { PreviousHopData(HTLCPreviousHopData), OutboundRoute { @@ -131,15 +132,23 @@ mod channel_held_info { } } } -pub(super) use self::channel_held_info::*; +pub(crate) use self::channel_held_info::*; + +/// payment_hash type, use to cross-lock hop +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +pub struct PaymentHash(pub [u8;32]); +/// payment_preimage type, use to route payment between hop +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] +pub struct PaymentPreimage(pub [u8;32]); -type ShutdownResult = (Vec, Vec<(HTLCSource, [u8; 32])>); +type ShutdownResult = (Vec, Vec<(HTLCSource, PaymentHash)>); /// Error type returned across the channel_state mutex boundary. When an Err is generated for a /// Channel, we generally end up with a ChannelError::Close for which we have to close the channel /// immediately (ie with no further calls on it made). Thus, this step happens inside a /// channel_state lock. We then return the set of things that need to be done outside the lock in /// this struct and call handle_error!() on it. + struct MsgHandleErrInternal { err: msgs::HandleError, shutdown_finish: Option<(ShutdownResult, Option)>, @@ -248,7 +257,7 @@ struct ChannelHolder { /// Note that while this is held in the same mutex as the channels themselves, no consistency /// guarantees are made about the channels given here actually existing anymore by the time you /// go to read them! - claimable_htlcs: HashMap<[u8; 32], Vec>, + claimable_htlcs: HashMap>, /// Messages to send to peers - pushed to in the same lock that they are generated in (except /// for broadcast messages, where ordering isn't as strict). pending_msg_events: Vec, @@ -258,7 +267,7 @@ struct MutChannelHolder<'a> { short_to_id: &'a mut HashMap, next_forward: &'a mut Instant, forward_htlcs: &'a mut HashMap>, - claimable_htlcs: &'a mut HashMap<[u8; 32], Vec>, + claimable_htlcs: &'a mut HashMap>, pending_msg_events: &'a mut Vec, } impl ChannelHolder { @@ -624,13 +633,7 @@ impl ChannelManager { for tx in local_txn { self.tx_broadcaster.broadcast_transaction(&tx); } - //TODO: We need to have a way where outbound HTLC claims can result in us claiming the - //now-on-chain HTLC output for ourselves (and, thereafter, passing the HTLC backwards). - //TODO: We need to handle monitoring of pending offered HTLCs which just hit the chain and - //may be claimed, resulting in us claiming the inbound HTLCs (and back-failing after - //timeouts are hit and our claims confirm). - //TODO: In any case, we need to make sure we remove any pending htlc tracking (via - //fail_backwards or claim_funds) eventually for all HTLCs that were in the channel + } /// Force closes a channel, immediately broadcasting the latest local commitment transaction to @@ -837,7 +840,7 @@ impl ChannelManager { } const ZERO:[u8; 21*65] = [0; 21*65]; - fn construct_onion_packet(mut payloads: Vec, onion_keys: Vec, associated_data: &[u8; 32]) -> msgs::OnionPacket { + fn construct_onion_packet(mut payloads: Vec, onion_keys: Vec, associated_data: &PaymentHash) -> msgs::OnionPacket { let mut buf = Vec::with_capacity(21*65); buf.resize(21*65, 0); @@ -874,7 +877,7 @@ impl ChannelManager { let mut hmac = Hmac::new(Sha256::new(), &keys.mu); hmac.input(&packet_data); - hmac.input(&associated_data[..]); + hmac.input(&associated_data.0[..]); hmac.raw_result(&mut hmac_res); } @@ -996,7 +999,7 @@ impl ChannelManager { let mut hmac = Hmac::new(Sha256::new(), &mu); hmac.input(&msg.onion_routing_packet.hop_data); - hmac.input(&msg.payment_hash); + hmac.input(&msg.payment_hash.0[..]); if hmac.result() != MacResult::new(&msg.onion_routing_packet.hmac) { return_err!("HMAC Check failed", 0x8000 | 0x4000 | 5, &get_onion_hash!()); } @@ -1194,7 +1197,7 @@ impl ChannelManager { /// /// Raises APIError::RoutError when invalid route or forward parameter /// (cltv_delta, fee, node public key) is specified - pub fn send_payment(&self, route: Route, payment_hash: [u8; 32]) -> Result<(), APIError> { + pub fn send_payment(&self, route: Route, payment_hash: PaymentHash) -> Result<(), APIError> { if route.hops.len() < 1 || route.hops.len() > 20 { return Err(APIError::RouteError{err: "Route didn't go anywhere/had bogus size"}); } @@ -1488,7 +1491,7 @@ impl ChannelManager { } /// Indicates that the preimage for payment_hash is unknown or the received amount is incorrect after a PaymentReceived event. - pub fn fail_htlc_backwards(&self, payment_hash: &[u8; 32], reason: PaymentFailReason) -> bool { + pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash, reason: PaymentFailReason) -> bool { let _ = self.total_consistency_lock.read().unwrap(); let mut channel_state = Some(self.channel_state.lock().unwrap()); @@ -1508,7 +1511,7 @@ impl ChannelManager { /// to fail and take the channel_state lock for each iteration (as we take ownership and may /// drop it). In other words, no assumptions are made that entries in claimable_htlcs point to /// still-available channels. - fn fail_htlc_backwards_internal(&self, mut channel_state_lock: MutexGuard, source: HTLCSource, payment_hash: &[u8; 32], onion_error: HTLCFailReason) { + fn fail_htlc_backwards_internal(&self, mut channel_state_lock: MutexGuard, source: HTLCSource, payment_hash: &PaymentHash, onion_error: HTLCFailReason) { match source { HTLCSource::OutboundRoute { .. } => { mem::drop(channel_state_lock); @@ -1526,7 +1529,8 @@ impl ChannelManager { rejected_by_dest: !payment_retryable, }); } else { - panic!("should have onion error packet here"); + //TODO: Pass this back (see GH #243) + //panic!("should have onion error packet here"); } }, HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret }) => { @@ -1580,11 +1584,11 @@ impl ChannelManager { /// should probably kick the net layer to go send messages if this returns true! /// /// May panic if called except in response to a PaymentReceived event. - pub fn claim_funds(&self, payment_preimage: [u8; 32]) -> bool { + pub fn claim_funds(&self, payment_preimage: PaymentPreimage) -> bool { let mut sha = Sha256::new(); - sha.input(&payment_preimage); - let mut payment_hash = [0; 32]; - sha.result(&mut payment_hash); + sha.input(&payment_preimage.0[..]); + let mut payment_hash = PaymentHash([0; 32]); + sha.result(&mut payment_hash.0[..]); let _ = self.total_consistency_lock.read().unwrap(); @@ -1598,7 +1602,7 @@ impl ChannelManager { true } else { false } } - fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard, source: HTLCSource, payment_preimage: [u8; 32]) { + fn claim_funds_internal(&self, mut channel_state_lock: MutexGuard, source: HTLCSource, payment_preimage: PaymentPreimage) { match source { HTLCSource::OutboundRoute { .. } => { mem::drop(channel_state_lock); @@ -2661,6 +2665,18 @@ impl ChainListener for ChannelManager { for failure in failed_channels.drain(..) { self.finish_force_close_channel(failure); } + { + let mut channel_state = Some(self.channel_state.lock().unwrap()); + for htlc_update in self.monitor.fetch_pending_htlc_updated() { + if let Some(preimage) = htlc_update.payment_preimage { + if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap());} + self.claim_funds_internal(channel_state.take().unwrap(), htlc_update.source, preimage); + } else { + if channel_state.is_none() { channel_state = Some(self.channel_state.lock().unwrap());} + self.fail_htlc_backwards_internal(channel_state.take().unwrap(), htlc_update.source, &htlc_update.payment_hash, HTLCFailReason::Reason { failure_code: 0x4000 | 10, data: Vec::new() }); + } + } + } self.latest_block_height.store(height as usize, Ordering::Release); *self.last_block_hash.try_lock().expect("block_(dis)connected must not be called in parallel") = header.bitcoin_hash(); } @@ -3271,8 +3287,9 @@ mod tests { use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor}; use chain::keysinterface; use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC}; - use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,OnionKeys,PaymentFailReason,RAACommitmentOrder}; + use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,OnionKeys,PaymentFailReason,RAACommitmentOrder, PaymentPreimage, PaymentHash}; use ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, CLTV_CLAIM_BUFFER, HTLC_FAIL_TIMEOUT_BLOCKS, ManyChannelMonitor}; + use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT}; use ln::router::{Route, RouteHop, Router}; use ln::msgs; use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler}; @@ -3433,7 +3450,7 @@ mod tests { }, ); - let packet = ChannelManager::construct_onion_packet(payloads, onion_keys, &[0x42; 32]); + let packet = ChannelManager::construct_onion_packet(payloads, onion_keys, &PaymentHash([0x42; 32])); // Just check the final packet encoding, as it includes all the per-hop vectors in it // anyway... assert_eq!(packet.encode(), hex::decode("0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a716a996c7845c93d90e4ecbb9bde4ece2f69425c99e4bc820e44485455f135edc0d10f7d61ab590531cf08000179a333a347f8b4072f216400406bdf3bf038659793d4a1fd7b246979e3150a0a4cb052c9ec69acf0f48c3d39cd55675fe717cb7d80ce721caad69320c3a469a202f1e468c67eaf7a7cd8226d0fd32f7b48084dca885d56047694762b67021713ca673929c163ec36e04e40ca8e1c6d17569419d3039d9a1ec866abe044a9ad635778b961fc0776dc832b3a451bd5d35072d2269cf9b040f6b7a7dad84fb114ed413b1426cb96ceaf83825665ed5a1d002c1687f92465b49ed4c7f0218ff8c6c7dd7221d589c65b3b9aaa71a41484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f9172307c7268724c3618e6817abd793adc214a0dc0bc616816632f27ea336fb56dfd").unwrap()); @@ -3908,24 +3925,37 @@ mod tests { assert!($node_a.node.get_and_clear_pending_msg_events().is_empty()); } } + }; + ($node_a: expr, $node_b: expr, $commitment_signed: expr, $fail_backward: expr, $extra_message: expr, $origin_failure: expr) => { + { + commitment_signed_dance!($node_a, $node_b, $commitment_signed, $fail_backward, true); + let events = $node_a.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::PaymentFailureNetworkUpdate { update: msgs::HTLCFailChannelUpdate::ChannelClosed { .. } } => { + //TODO: check when fail_htlc_backward_internal after fecth_pending_htlcs have consistent error code + }, + _ => { panic!("Unexpected event"); } + } + } } } macro_rules! get_payment_preimage_hash { ($node: expr) => { { - let payment_preimage = [*$node.network_payment_count.borrow(); 32]; + let payment_preimage = PaymentPreimage([*$node.network_payment_count.borrow(); 32]); *$node.network_payment_count.borrow_mut() += 1; - let mut payment_hash = [0; 32]; + let mut payment_hash = PaymentHash([0; 32]); let mut sha = Sha256::new(); - sha.input(&payment_preimage[..]); - sha.result(&mut payment_hash); + sha.input(&payment_preimage.0[..]); + sha.result(&mut payment_hash.0[..]); (payment_preimage, payment_hash) } } } - fn send_along_route(origin_node: &Node, route: Route, expected_route: &[&Node], recv_value: u64) -> ([u8; 32], [u8; 32]) { + fn send_along_route(origin_node: &Node, route: Route, expected_route: &[&Node], recv_value: u64) -> (PaymentPreimage, PaymentHash) { let (our_payment_preimage, our_payment_hash) = get_payment_preimage_hash!(origin_node); let mut payment_event = { @@ -3979,7 +4009,7 @@ mod tests { (our_payment_preimage, our_payment_hash) } - fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_preimage: [u8; 32]) { + fn claim_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_preimage: PaymentPreimage) { assert!(expected_route.last().unwrap().node.claim_funds(our_payment_preimage)); check_added_monitors!(expected_route.last().unwrap(), 1); @@ -4064,13 +4094,13 @@ mod tests { } } - fn claim_payment(origin_node: &Node, expected_route: &[&Node], our_payment_preimage: [u8; 32]) { + fn claim_payment(origin_node: &Node, expected_route: &[&Node], our_payment_preimage: PaymentPreimage) { claim_payment_along_route(origin_node, expected_route, false, our_payment_preimage); } const TEST_FINAL_CLTV: u32 = 32; - fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u64) -> ([u8; 32], [u8; 32]) { + fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u64) -> (PaymentPreimage, PaymentHash) { let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), None, &Vec::new(), recv_value, TEST_FINAL_CLTV).unwrap(); assert_eq!(route.hops.len(), expected_route.len()); for (node, hop) in expected_route.iter().zip(route.hops.iter()) { @@ -4101,7 +4131,7 @@ mod tests { claim_payment(&origin, expected_route, our_payment_preimage); } - fn fail_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_hash: [u8; 32]) { + fn fail_payment_along_route(origin_node: &Node, expected_route: &[&Node], skip_last: bool, our_payment_hash: PaymentHash) { assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash, PaymentFailReason::PreimageUnknown)); check_added_monitors!(expected_route.last().unwrap(), 1); @@ -4166,7 +4196,7 @@ mod tests { } } - fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: [u8; 32]) { + fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: PaymentHash) { fail_payment_along_route(origin_node, expected_route, false, our_payment_hash); } @@ -5310,7 +5340,11 @@ mod tests { false } else { true } }); - assert_eq!(res.len(), 2); + assert!(res.len() >= 2); + assert!(res.len() == 2 || res.len() == 3); + if res.len() == 3 { + assert_eq!(res[1], res[2]); + } } assert!(node_txn.is_empty()); @@ -5825,7 +5859,7 @@ mod tests { assert_eq!(revoked_local_txn[0].output.len(), 2); // Only HTLC and output back to 0 are present assert_eq!(revoked_local_txn[1].input.len(), 1); assert_eq!(revoked_local_txn[1].input[0].previous_output.txid, revoked_local_txn[0].txid()); - assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), 133); // HTLC-Timeout + assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC-Timeout // Revoke the old state claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_3); @@ -5944,7 +5978,7 @@ mod tests { assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_1.3.txid()); assert_eq!(revoked_local_txn[1].input.len(), 1); assert_eq!(revoked_local_txn[1].input[0].previous_output.txid, revoked_local_txn[0].txid()); - assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), 133); // HTLC-Timeout + assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC-Timeout check_spends!(revoked_local_txn[1], revoked_local_txn[0].clone()); //Revoke the old state @@ -5970,8 +6004,8 @@ mod tests { witness_lens.insert(node_txn[0].input[2].witness.last().unwrap().len()); assert_eq!(witness_lens.len(), 3); assert_eq!(*witness_lens.iter().skip(0).next().unwrap(), 77); // revoked to_local - assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), 133); // revoked offered HTLC - assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), 138); // revoked received HTLC + assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), OFFERED_HTLC_SCRIPT_WEIGHT); // revoked offered HTLC + assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // revoked received HTLC // Next nodes[1] broadcasts its current local tx state: assert_eq!(node_txn[1].input.len(), 1); @@ -5979,7 +6013,7 @@ mod tests { assert_eq!(node_txn[2].input.len(), 1); let witness_script = node_txn[2].clone().input[0].witness.pop().unwrap(); - assert_eq!(witness_script.len(), 133); //Spending an offered htlc output + assert_eq!(witness_script.len(), OFFERED_HTLC_SCRIPT_WEIGHT); //Spending an offered htlc output assert_eq!(node_txn[2].input[0].previous_output.txid, node_txn[1].txid()); assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid); assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[1].previous_output.txid); @@ -6042,15 +6076,15 @@ mod tests { witness_lens.insert(node_txn[2].input[0].witness.last().unwrap().len()); assert_eq!(witness_lens.len(), 3); assert_eq!(*witness_lens.iter().skip(0).next().unwrap(), 77); // revoked to_local - assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), 133); // revoked offered HTLC - assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), 138); // revoked received HTLC + assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), OFFERED_HTLC_SCRIPT_WEIGHT); // revoked offered HTLC + assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), ACCEPTED_HTLC_SCRIPT_WEIGHT); // revoked received HTLC assert_eq!(node_txn[3].input.len(), 1); check_spends!(node_txn[3], chan_1.3.clone()); assert_eq!(node_txn[4].input.len(), 1); let witness_script = node_txn[4].input[0].witness.last().unwrap(); - assert_eq!(witness_script.len(), 133); //Spending an offered htlc output + assert_eq!(witness_script.len(), OFFERED_HTLC_SCRIPT_WEIGHT); //Spending an offered htlc output assert_eq!(node_txn[4].input[0].previous_output.txid, node_txn[3].txid()); assert_ne!(node_txn[4].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid); assert_ne!(node_txn[4].input[0].previous_output.txid, node_txn[1].input[0].previous_output.txid); @@ -6060,6 +6094,323 @@ mod tests { assert_eq!(nodes[1].node.list_channels().len(), 0); } + #[test] + fn test_htlc_on_chain_success() { + // Test that in case of an unilateral close onchain, we detect the state of output thanks to + // ChainWatchInterface and pass the preimage backward accordingly. So here we test that ChannelManager is + // broadcasting the right event to other nodes in payment path. + // A --------------------> B ----------------------> C (preimage) + // C's commitment tx + // \ + // C's HTLC Success tx + + let nodes = create_network(3); + + // Create some initial channels + let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1); + let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); + + // Rebalance the network a bit by relaying one payment through all the channels... + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + + let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; + + // Broadcast legit commitment tx from C on B's chain + // Broadcast HTLC Success transation by C on received output from C's commitment tx on B's chain + let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone(); + check_spends!(commitment_tx[0], chan_2.3.clone()); + nodes[2].node.claim_funds(payment_preimage); + { + let mut added_monitors = nodes[2].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(update_fail_htlcs.is_empty()); + assert!(!update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[1].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1); + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Success tx), ChannelMonitor : 1 (HTLC-Success tx) + assert_eq!(node_txn.len(), 3); + check_spends!(node_txn[0], commitment_tx[0].clone()); + assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_2.3.clone()); + check_spends!(node_txn[2], node_txn[1].clone()); + assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71); + assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + + // Verify that B's ChannelManager is able to extract preimage from HTLC Success tx and pass it backward + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: node_txn}, 1); + { + let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 2); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + match events[1] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(update_fail_htlcs.is_empty()); + assert!(!update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + { + let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 (timeout tx) * 2 (block-rescan) + assert_eq!(node_txn.len(), 4); + assert_eq!(node_txn[0], node_txn[3]); + check_spends!(node_txn[0], commitment_tx[0].clone()); + check_spends!(node_txn[3], commitment_tx[0].clone()); + assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + assert_eq!(node_txn[3].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_2.3.clone()); + check_spends!(node_txn[2], node_txn[1].clone()); + assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71); + assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + node_txn.clear(); + } + + // Broadcast legit commitment tx from A on B's chain + // Broadcast preimage tx by B on offered output from A commitment tx on A's chain + let commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone(); + check_spends!(commitment_tx[0], chan_1.3.clone()); + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1); + let events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 (commitment tx), ChannelMonitor : 1 (HTLC-Success) * 2 (block-rescan) + assert_eq!(node_txn.len(), 3); + assert_eq!(node_txn[0], node_txn[2]); + check_spends!(node_txn[0], commitment_tx[0].clone()); + assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[2], commitment_tx[0].clone()); + assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_1.3.clone()); + assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71); + let commitment_tx = node_txn[1].clone(); + + // Verify that A's ChannelManager is able to extract preimage from preimage tx and pass it backward + nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: node_txn }, 1); + let events = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 (timeout tx) * 2 (block-rescan) + assert_eq!(node_txn.len(), 4); + assert_eq!(node_txn[0], node_txn[3]); + check_spends!(node_txn[0], commitment_tx.clone()); + check_spends!(node_txn[3], commitment_tx.clone()); + assert_eq!(node_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + assert_eq!(node_txn[3].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_1.3.clone()); + check_spends!(node_txn[2], node_txn[1].clone()); + assert_eq!(node_txn[1].input[0].witness.clone().last().unwrap().len(), 71); + assert_eq!(node_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + } + + #[test] + fn test_htlc_on_chain_timeout() { + // Test that in case of an unilateral close onchain, we detect the state of output thanks to + // ChainWatchInterface and timeout the HTLC bacward accordingly. So here we test that ChannelManager is + // broadcasting the right event to other nodes in payment path. + // A ------------------> B ----------------------> C (timeout) + // B's commitment tx C's commitment tx + // \ \ + // B's HTLC timeout tx B's timeout tx + + let nodes = create_network(3); + + // Create some intial channels + let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1); + let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); + + // Rebalance the network a bit by relaying one payment thorugh all the channels... + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + + let (_payment_preimage, payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; + + // Brodacast legit commitment tx from C on B's chain + let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone(); + check_spends!(commitment_tx[0], chan_2.3.clone()); + nodes[2].node.fail_htlc_backwards(&payment_hash, PaymentFailReason::PreimageUnknown); + { + let mut added_monitors = nodes[2].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(!update_fail_htlcs.is_empty()); + assert!(update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[1].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1); + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {}, + _ => panic!("Unexpected event"), + } + let node_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 1 (commitment tx) + assert_eq!(node_txn.len(), 1); + check_spends!(node_txn[0], chan_2.3.clone()); + assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 71); + + // Broadcast timeout transaction by B on received output fron C's commitment tx on B's chain + // Verify that B's ChannelManager is able to detect that HTLC is timeout by its own tx and react backward in consequence + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 200); + let timeout_tx; + { + let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(node_txn.len(), 8); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 6 (HTLC-Timeout tx, commitment tx, timeout tx) * 2 (block-rescan) + assert_eq!(node_txn[0], node_txn[5]); + assert_eq!(node_txn[1], node_txn[6]); + assert_eq!(node_txn[2], node_txn[7]); + check_spends!(node_txn[0], commitment_tx[0].clone()); + assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_2.3.clone()); + check_spends!(node_txn[2], node_txn[1].clone()); + assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), 71); + assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[3], chan_2.3.clone()); + check_spends!(node_txn[4], node_txn[3].clone()); + assert_eq!(node_txn[3].input[0].witness.clone().last().unwrap().len(), 71); + assert_eq!(node_txn[4].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + timeout_tx = node_txn[0].clone(); + node_txn.clear(); + } + + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![timeout_tx]}, 1); + { + let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 2); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {}, + _ => panic!("Unexpected event"), + } + match events[1] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(!update_fail_htlcs.is_empty()); + assert!(update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // Well... here we detect our own htlc_timeout_tx so no tx to be generated + assert_eq!(node_txn.len(), 0); + + // Broadcast legit commitment tx from B on A's chain + let commitment_tx = nodes[1].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone(); + check_spends!(commitment_tx[0], chan_1.3.clone()); + + nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 200); + let events = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {}, + _ => panic!("Unexpected event"), + } + let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 2 (timeout tx) * 2 block-rescan + assert_eq!(node_txn.len(), 4); + assert_eq!(node_txn[0], node_txn[3]); + check_spends!(node_txn[0], commitment_tx[0].clone()); + assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(node_txn[1], chan_1.3.clone()); + check_spends!(node_txn[2], node_txn[1].clone()); + assert_eq!(node_txn[1].clone().input[0].witness.last().unwrap().len(), 71); + assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + } + + #[test] + fn test_commitment_revoked_fail_backward() { + // Test that in case of a revoked commitment tx, we detect the resolution of output by justice tx + // and fail backward accordingly. + + let nodes = create_network(3); + + // Create some initial channels + create_announced_chan_between_nodes(&nodes, 0, 1); + let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); + + // Rebalance the network a bit by relaying one payment through all the channels... + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + + let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 3000000); + // Get the will-be-revoked local txn from nodes[2] + let revoked_local_txn = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone(); + // Revoke the old state + claim_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], payment_preimage); + + route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 3000000); + + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1); + { + let mut added_monitors = nodes[1].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 2); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { msg: msgs::ChannelUpdate { .. } } => {}, + _ => panic!("Unexpected event"), + } + match events[1] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(!update_fail_htlcs.is_empty()); + assert!(update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + } + } + #[test] fn test_htlc_ignore_latest_remote_commitment() { // Test that HTLC transactions spending the latest remote commitment transaction are simply @@ -7896,7 +8247,7 @@ mod tests { let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 1 (local commitment tx), ChannelMonitor: 2 (1 preimage tx) * 2 (block-rescan) check_spends!(node_txn[0], commitment_tx[0].clone()); assert_eq!(node_txn[0], node_txn[2]); - assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 133); + assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); check_spends!(node_txn[1], chan_1.3.clone()); let spend_txn = check_spendable_outputs!(nodes[1], 1); // , 0, 0, 1, 1); @@ -7961,10 +8312,12 @@ mod tests { _ => panic!("Unexpected event"), } let revoked_htlc_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); - assert_eq!(revoked_htlc_txn.len(), 2); + assert_eq!(revoked_htlc_txn.len(), 3); + assert_eq!(revoked_htlc_txn[0], revoked_htlc_txn[2]); assert_eq!(revoked_htlc_txn[0].input.len(), 1); - assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 133); + assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0].clone()); + check_spends!(revoked_htlc_txn[1], chan_1.3.clone()); // B will generate justice tx from A's revoked commitment/HTLC tx nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] }, 1); @@ -8011,9 +8364,10 @@ mod tests { } let revoked_htlc_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); - assert_eq!(revoked_htlc_txn.len(), 2); + assert_eq!(revoked_htlc_txn.len(), 3); + assert_eq!(revoked_htlc_txn[0], revoked_htlc_txn[2]); assert_eq!(revoked_htlc_txn[0].input.len(), 1); - assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), 138); + assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0].clone()); // A will generate justice tx from B's revoked commitment/HTLC tx @@ -8039,6 +8393,210 @@ mod tests { check_spends!(spend_txn[4], node_txn[3].clone()); // spending justice tx output on htlc success tx } + #[test] + fn test_onchain_to_onchain_claim() { + // Test that in case of channel closure, we detect the state of output thanks to + // ChainWatchInterface and claim HTLC on downstream peer's remote commitment tx. + + let nodes = create_network(3); + + // Create some initial channels + let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1); + let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); + + // Rebalance the network a bit by relaying one payment through all the channels ... + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 8000000); + + let (payment_preimage, _payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2]), 3000000); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42}; + let commitment_tx = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone(); + check_spends!(commitment_tx[0], chan_2.3.clone()); + nodes[2].node.claim_funds(payment_preimage); + { + let mut added_monitors = nodes[2].chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(update_fail_htlcs.is_empty()); + assert!(!update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[1].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1); + let events = nodes[2].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + + let c_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Success tx), ChannelMonitor : 1 (HTLC-Success tx) + assert_eq!(c_txn.len(), 3); + check_spends!(c_txn[0], commitment_tx[0].clone()); + assert_eq!(c_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(c_txn[1], chan_2.3.clone()); + check_spends!(c_txn[2], c_txn[1].clone()); + assert_eq!(c_txn[1].input[0].witness.clone().last().unwrap().len(), 71); + assert_eq!(c_txn[2].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + + // So we broadcast C's commitment tx and HTLC-Success on B's chain, we should successfully be able to extract preimage and update downstream monitor + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![c_txn[1].clone(), c_txn[2].clone()]}, 1); + { + let mut b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(b_txn.len(), 4); + assert_eq!(b_txn[0], b_txn[3]); + check_spends!(b_txn[1], chan_2.3); // B local commitment tx, issued by ChannelManager + check_spends!(b_txn[2], b_txn[1].clone()); // HTLC-Timeout on B local commitment tx, issued by ChannelManager + assert_eq!(b_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + check_spends!(b_txn[0], c_txn[1].clone()); // timeout tx on C remote commitment tx, issued by ChannelMonitor, * 2 due to block rescan + assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + b_txn.clear(); + } + check_added_monitors!(nodes[1], 1); + let msg_events = nodes[1].node.get_and_clear_pending_msg_events(); + match msg_events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + match msg_events[1] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(update_fail_htlcs.is_empty()); + assert!(!update_fulfill_htlcs.is_empty()); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + }; + // Broadcast A's commitment tx on B's chain to see if we are able to claim inbound HTLC with our HTLC-Success tx + let commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone(); + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1); + let b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); + check_spends!(b_txn[1], chan_1.3); // Local commitment tx, issued by ChannelManager + assert_eq!(b_txn[0], b_txn[2]); // HTLC-Success tx, issued by ChannelMonitor, * 2 due to block rescan + check_spends!(b_txn[0], commitment_tx[0].clone()); + assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + let msg_events = nodes[1].node.get_and_clear_pending_msg_events(); + match msg_events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexpected event"), + } + } + + #[test] + fn test_duplicate_payment_hash_one_failure_one_success() { + // Topology : A --> B --> C + // We route 2 payments with same hash between B and C, one will be timeout, the other successfully claim + let mut nodes = create_network(3); + + create_announced_chan_between_nodes(&nodes, 0, 1); + let chan_2 = create_announced_chan_between_nodes(&nodes, 1, 2); + + let (payment_preimage, duplicate_payment_hash) = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000); + *nodes[0].network_payment_count.borrow_mut() -= 1; + route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 900000); + + let commitment_txn = nodes[2].node.channel_state.lock().unwrap().by_id.get(&chan_2.2).unwrap().last_local_commitment_txn.clone(); + assert_eq!(commitment_txn[0].input.len(), 1); + check_spends!(commitment_txn[0], chan_2.3.clone()); + + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_txn[0].clone()] }, 1); + let htlc_timeout_tx; + { + let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(node_txn[0], node_txn[5]); + assert_eq!(node_txn[1], node_txn[6]); + check_spends!(node_txn[0], commitment_txn[0].clone()); + check_spends!(node_txn[1], commitment_txn[0].clone()); + check_spends!(node_txn[2], chan_2.3.clone()); + check_spends!(node_txn[3], node_txn[2].clone()); + check_spends!(node_txn[4], node_txn[2].clone()); + htlc_timeout_tx = node_txn[1].clone(); + } + + let events = nodes[1].node.get_and_clear_pending_msg_events(); + match events[0] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexepected event"), + } + + nodes[2].node.claim_funds(payment_preimage); + nodes[2].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![commitment_txn[0].clone()] }, 1); + check_added_monitors!(nodes[2], 2); + let events = nodes[2].node.get_and_clear_pending_msg_events(); + match events[0] { + MessageSendEvent::UpdateHTLCs { .. } => {}, + _ => panic!("Unexpected event"), + } + match events[1] { + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + _ => panic!("Unexepected event"), + } + let htlc_success_txn = nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap(); + check_spends!(htlc_success_txn[2], chan_2.3.clone()); + assert_eq!(htlc_success_txn[0], htlc_success_txn[3]); + assert_eq!(htlc_success_txn[0].input.len(), 1); + assert_eq!(htlc_success_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + assert_eq!(htlc_success_txn[1], htlc_success_txn[4]); + assert_eq!(htlc_success_txn[1].input.len(), 1); + assert_eq!(htlc_success_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); + check_spends!(htlc_success_txn[0], commitment_txn[0].clone()); + check_spends!(htlc_success_txn[1], commitment_txn[0].clone()); + + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![htlc_timeout_tx] }, 200); + check_added_monitors!(nodes[1], 1); + let msg_events = nodes[1].node.get_and_clear_pending_msg_events(); + let htlc_updates = match msg_events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, ref updates } => { + assert!(updates.update_add_htlcs.is_empty()); + assert_eq!(updates.update_fail_htlcs.len(), 1); + assert_eq!(updates.update_fail_htlcs[0].htlc_id, 1); + assert!(updates.update_fulfill_htlcs.is_empty()); + assert!(updates.update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + (*updates).clone() + }, + _ => panic!("Unexpected event"), + }; + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_updates.update_fail_htlcs[0]).unwrap(); + let events = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 0); + commitment_signed_dance!(nodes[0], nodes[1], &htlc_updates.commitment_signed, false, false, nodes[2].node.get_our_node_id()); + let events = nodes[0].node.get_and_clear_pending_events(); + match events[0] { + Event::PaymentFailed { ref payment_hash, .. } => { + assert_eq!(*payment_hash, duplicate_payment_hash); + } + _ => panic!("Unexpected event"), + } + + // Solve 2nd HTLC by broadcasting on B's chain HTLC-Success Tx from C + nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![htlc_success_txn[0].clone()] }, 200); + check_added_monitors!(nodes[1], 1); + let events = nodes[1].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + match events[0] { + MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, .. } } => { + assert!(update_add_htlcs.is_empty()); + assert!(update_fail_htlcs.is_empty()); + assert_eq!(update_fulfill_htlcs.len(), 1); + assert_eq!(update_fulfill_htlcs[0].htlc_id, 0); + assert!(update_fail_malformed_htlcs.is_empty()); + assert_eq!(nodes[0].node.get_our_node_id(), *node_id); + }, + _ => panic!("Unexpected event"), + } + } + #[test] fn test_dynamic_spendable_outputs_local_htlc_success_tx() { let nodes = create_network(2); @@ -8067,13 +8625,14 @@ mod tests { } let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn[0].input.len(), 1); - assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 138); + assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); check_spends!(node_txn[0], local_txn[0].clone()); // Verify that B is able to spend its own HTLC-Success tx thanks to spendable output event given back by its ChannelMonitor let spend_txn = check_spendable_outputs!(nodes[1], 1); - assert_eq!(spend_txn.len(), 1); + assert_eq!(spend_txn.len(), 2); check_spends!(spend_txn[0], node_txn[0].clone()); + check_spends!(spend_txn[1], node_txn[2].clone()); } #[test] @@ -8098,14 +8657,18 @@ mod tests { } let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn[0].input.len(), 1); - assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), 133); + assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); check_spends!(node_txn[0], local_txn[0].clone()); // Verify that A is able to spend its own HTLC-Timeout tx thanks to spendable output event given back by its ChannelMonitor let spend_txn = check_spendable_outputs!(nodes[0], 1); - assert_eq!(spend_txn.len(), 4); + assert_eq!(spend_txn.len(), 8); assert_eq!(spend_txn[0], spend_txn[2]); + assert_eq!(spend_txn[0], spend_txn[4]); + assert_eq!(spend_txn[0], spend_txn[6]); assert_eq!(spend_txn[1], spend_txn[3]); + assert_eq!(spend_txn[1], spend_txn[5]); + assert_eq!(spend_txn[1], spend_txn[7]); check_spends!(spend_txn[0], local_txn[0].clone()); check_spends!(spend_txn[1], node_txn[0].clone()); } diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index 7faeae68a0c..f229886079d 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -29,6 +29,8 @@ use secp256k1; use ln::msgs::DecodeError; use ln::chan_utils; use ln::chan_utils::HTLCOutputInCommitment; +use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; +use ln::channel::{ACCEPTED_HTLC_SCRIPT_WEIGHT, OFFERED_HTLC_SCRIPT_WEIGHT}; use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface}; use chain::transaction::OutPoint; use chain::keysinterface::SpendableOutputDescriptor; @@ -37,7 +39,7 @@ use util::ser::{ReadableArgs, Readable, Writer, Writeable, WriterWriteAdaptor, U use util::sha2::Sha256; use util::{byte_utils, events}; -use std::collections::HashMap; +use std::collections::{HashMap, hash_map}; use std::sync::{Arc,Mutex}; use std::{hash,cmp, mem}; @@ -82,6 +84,14 @@ pub enum ChannelMonitorUpdateErr { #[derive(Debug)] pub struct MonitorUpdateError(pub &'static str); +/// Simple structure send back by ManyChannelMonitor in case of HTLC detected onchain from a +/// forward channel and from which info are needed to update HTLC in a backward channel. +pub struct HTLCUpdate { + pub(super) payment_hash: PaymentHash, + pub(super) payment_preimage: Option, + pub(super) source: HTLCSource +} + /// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between /// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing /// events to it, while also taking any add_update_monitor events and passing them to some remote @@ -98,6 +108,10 @@ pub trait ManyChannelMonitor: Send + Sync { /// ChainWatchInterfaces such that the provided monitor receives block_connected callbacks with /// any spends of it. fn add_update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; + + /// Used by ChannelManager to get list of HTLC resolved onchain and which needed to be updated + /// with success or failure backward + fn fetch_pending_htlc_updated(&self) -> Vec; } /// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a @@ -119,6 +133,7 @@ pub struct SimpleManyChannelMonitor { chain_monitor: Arc, broadcaster: Arc, pending_events: Mutex>, + pending_htlc_updated: Mutex, HTLCSource)>>>, logger: Arc, } @@ -126,20 +141,47 @@ impl ChainListener for SimpleManyChannelMonit fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) { let block_hash = header.bitcoin_hash(); let mut new_events: Vec = Vec::with_capacity(0); + let mut htlc_updated_infos = Vec::new(); { let mut monitors = self.monitors.lock().unwrap(); for monitor in monitors.values_mut() { - let (txn_outputs, spendable_outputs) = monitor.block_connected(txn_matched, height, &block_hash, &*self.broadcaster); + let (txn_outputs, spendable_outputs, mut htlc_updated) = monitor.block_connected(txn_matched, height, &block_hash, &*self.broadcaster); if spendable_outputs.len() > 0 { new_events.push(events::Event::SpendableOutputs { outputs: spendable_outputs, }); } + for (ref txid, ref outputs) in txn_outputs { for (idx, output) in outputs.iter().enumerate() { self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey); } } + htlc_updated_infos.append(&mut htlc_updated); + } + } + { + // ChannelManager will just need to fetch pending_htlc_updated and pass state backward + let mut pending_htlc_updated = self.pending_htlc_updated.lock().unwrap(); + for htlc in htlc_updated_infos.drain(..) { + match pending_htlc_updated.entry(htlc.2) { + hash_map::Entry::Occupied(mut e) => { + // In case of reorg we may have htlc outputs solved in a different way so + // Vacant or Occupied we update key-value with last state of tx resolvation + // We need also to keep only one state per-htlc so prune old one in case of + // block re-scan + e.get_mut().retain(|htlc_data| { + if htlc.0 == htlc_data.1 { + return false; + } + true + }); + e.get_mut().push((htlc.1, htlc.0)); + } + hash_map::Entry::Vacant(e) => { + e.insert(vec![(htlc.1, htlc.0)]); + } + } } } let mut pending_events = self.pending_events.lock().unwrap(); @@ -158,6 +200,7 @@ impl SimpleManyChannelMonitor chain_monitor, broadcaster, pending_events: Mutex::new(Vec::new()), + pending_htlc_updated: Mutex::new(HashMap::new()), logger, }); let weak_res = Arc::downgrade(&res); @@ -195,6 +238,7 @@ impl SimpleManyChannelMonitor monitors.insert(key, monitor); Ok(()) } + } impl ManyChannelMonitor for SimpleManyChannelMonitor { @@ -204,6 +248,21 @@ impl ManyChannelMonitor for SimpleManyChannelMonitor { Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), } } + + fn fetch_pending_htlc_updated(&self) -> Vec { + let mut updated = self.pending_htlc_updated.lock().unwrap(); + let mut pending_htlcs_updated = Vec::with_capacity(updated.len()); + for (k, v) in updated.drain() { + for htlc_data in v { + pending_htlcs_updated.push(HTLCUpdate { + payment_hash: k, + payment_preimage: htlc_data.0, + source: htlc_data.1 + }); + } + } + pending_htlcs_updated + } } impl events::EventsProvider for SimpleManyChannelMonitor { @@ -256,7 +315,7 @@ struct LocalSignedTx { b_htlc_key: PublicKey, delayed_payment_key: PublicKey, feerate_per_kw: u64, - htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>, + htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature, Option)>, } const SERIALIZATION_VERSION: u8 = 1; @@ -281,7 +340,7 @@ pub struct ChannelMonitor { their_to_self_delay: Option, old_secrets: [([u8; 32], u64); 49], - remote_claimable_outpoints: HashMap>, + remote_claimable_outpoints: HashMap)>>, /// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain. /// Nor can we figure out their commitment numbers without the commitment transaction they are /// spending. Thus, in order to claim them via revocation key, we track all the remote @@ -292,7 +351,7 @@ pub struct ChannelMonitor { /// Maps payment_hash values to commitment numbers for remote transactions for non-revoked /// remote transactions (ie should remain pretty small). /// Serialized to disk but should generally not be sent to Watchtowers. - remote_hash_commitment_number: HashMap<[u8; 32], u64>, + remote_hash_commitment_number: HashMap, // We store two local commitment transactions to avoid any race conditions where we may update // some monitors (potentially on watchtowers) but then fail to update others, resulting in the @@ -305,7 +364,7 @@ pub struct ChannelMonitor { // deserialization current_remote_commitment_number: u64, - payment_preimages: HashMap<[u8; 32], [u8; 32]>, + payment_preimages: HashMap, destination_script: Script, @@ -437,13 +496,13 @@ impl ChannelMonitor { let remote_hash_commitment_number = &mut self.remote_hash_commitment_number; self.payment_preimages.retain(|&k, _| { - for &(ref htlc, _, _) in &local_signed_commitment_tx.htlc_outputs { + for &(ref htlc, _, _, _) in &local_signed_commitment_tx.htlc_outputs { if k == htlc.payment_hash { return true } } if let Some(prev_local_commitment_tx) = prev_local_signed_commitment_tx { - for &(ref htlc, _, _) in prev_local_commitment_tx.htlc_outputs.iter() { + for &(ref htlc, _, _, _) in prev_local_commitment_tx.htlc_outputs.iter() { if k == htlc.payment_hash { return true } @@ -469,14 +528,21 @@ impl ChannelMonitor { /// The monitor watches for it to be broadcasted and then uses the HTLC information (and /// possibly future revocation/preimage information) to claim outputs where possible. /// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers. - pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec, commitment_number: u64, their_revocation_point: PublicKey) { + pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option)>, commitment_number: u64, their_revocation_point: PublicKey) { // TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction // so that a remote monitor doesn't learn anything unless there is a malicious close. // (only maybe, sadly we cant do the same for local info, as we need to be aware of // timeouts) - for htlc in &htlc_outputs { + for &(ref htlc, _) in &htlc_outputs { self.remote_hash_commitment_number.insert(htlc.payment_hash, commitment_number); } + // We prune old claimable outpoints, useless to pass backward state when remote commitment + // tx get revoked, optimize for storage + for (_, htlc_data) in self.remote_claimable_outpoints.iter_mut() { + for &mut(_, ref mut source) in htlc_data.iter_mut() { + source.take(); + } + } self.remote_claimable_outpoints.insert(unsigned_commitment_tx.txid(), htlc_outputs); self.current_remote_commitment_number = commitment_number; //TODO: Merge this into the other per-remote-transaction output storage stuff @@ -507,7 +573,7 @@ impl ChannelMonitor { /// Panics if set_their_to_self_delay has never been called. /// Also update Storage with latest local per_commitment_point to derive local_delayedkey in /// case of onchain HTLC tx - pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>) { + pub(super) fn provide_latest_local_commitment_tx_info(&mut self, signed_commitment_tx: Transaction, local_keys: chan_utils::TxCreationKeys, feerate_per_kw: u64, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature, Option)>) { assert!(self.their_to_self_delay.is_some()); self.prev_local_signed_commitment_tx = self.current_local_signed_commitment_tx.take(); self.current_local_signed_commitment_tx = Some(LocalSignedTx { @@ -530,7 +596,7 @@ impl ChannelMonitor { /// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all /// commitment_tx_infos which contain the payment hash have been revoked. - pub(super) fn provide_payment_preimage(&mut self, payment_hash: &[u8; 32], payment_preimage: &[u8; 32]) { + pub(super) fn provide_payment_preimage(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage) { self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone()); } @@ -746,17 +812,30 @@ impl ChannelMonitor { writer.write_all(&[$htlc_output.offered as u8; 1])?; writer.write_all(&byte_utils::be64_to_array($htlc_output.amount_msat))?; writer.write_all(&byte_utils::be32_to_array($htlc_output.cltv_expiry))?; - writer.write_all(&$htlc_output.payment_hash)?; + writer.write_all(&$htlc_output.payment_hash.0[..])?; writer.write_all(&byte_utils::be32_to_array($htlc_output.transaction_output_index))?; } } + macro_rules! serialize_htlc_source { + ($htlc_source: expr) => { + if let &Some(ref source) = $htlc_source { + writer.write_all(&[1; 1])?; + source.write(writer)?; + } else { + writer.write_all(&[0; 1])?; + } + } + } + + writer.write_all(&byte_utils::be64_to_array(self.remote_claimable_outpoints.len() as u64))?; - for (ref txid, ref htlc_outputs) in self.remote_claimable_outpoints.iter() { + for (ref txid, ref htlc_infos) in self.remote_claimable_outpoints.iter() { writer.write_all(&txid[..])?; - writer.write_all(&byte_utils::be64_to_array(htlc_outputs.len() as u64))?; - for htlc_output in htlc_outputs.iter() { + writer.write_all(&byte_utils::be64_to_array(htlc_infos.len() as u64))?; + for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() { serialize_htlc_in_commitment!(htlc_output); + serialize_htlc_source!(htlc_source); } } @@ -773,7 +852,7 @@ impl ChannelMonitor { if for_local_storage { writer.write_all(&byte_utils::be64_to_array(self.remote_hash_commitment_number.len() as u64))?; for (ref payment_hash, commitment_number) in self.remote_hash_commitment_number.iter() { - writer.write_all(*payment_hash)?; + writer.write_all(&payment_hash.0[..])?; writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; } } else { @@ -796,10 +875,11 @@ impl ChannelMonitor { writer.write_all(&byte_utils::be64_to_array($local_tx.feerate_per_kw))?; writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_outputs.len() as u64))?; - for &(ref htlc_output, ref their_sig, ref our_sig) in $local_tx.htlc_outputs.iter() { + for &(ref htlc_output, ref their_sig, ref our_sig, ref htlc_source) in $local_tx.htlc_outputs.iter() { serialize_htlc_in_commitment!(htlc_output); writer.write_all(&their_sig.serialize_compact(&self.secp_ctx))?; writer.write_all(&our_sig.serialize_compact(&self.secp_ctx))?; + serialize_htlc_source!(htlc_source); } } } @@ -826,7 +906,7 @@ impl ChannelMonitor { writer.write_all(&byte_utils::be64_to_array(self.payment_preimages.len() as u64))?; for payment_preimage in self.payment_preimages.values() { - writer.write_all(payment_preimage)?; + writer.write_all(&payment_preimage.0[..])?; } self.last_block_hash.write(writer)?; @@ -896,12 +976,15 @@ impl ChannelMonitor { /// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a /// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for /// HTLC-Success/HTLC-Timeout transactions. - fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Sha256dHash, Vec), Vec) { + /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of + /// revoked remote commitment tx + fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Sha256dHash, Vec), Vec, Vec<(HTLCSource, Option, PaymentHash)>) { // Most secp and related errors trying to create keys means we have no hope of constructing // a spend transaction...so we return no transactions to broadcast let mut txn_to_broadcast = Vec::new(); let mut watch_outputs = Vec::new(); let mut spendable_outputs = Vec::new(); + let mut htlc_updated = Vec::new(); let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers! let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid); @@ -910,7 +993,7 @@ impl ChannelMonitor { ( $thing : expr ) => { match $thing { Ok(a) => a, - Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs) + Err(_) => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated) } }; } @@ -935,7 +1018,7 @@ impl ChannelMonitor { }; let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key.unwrap())); let a_htlc_key = match self.their_htlc_base_key { - None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs), + None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated), Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &their_htlc_base_key)), }; @@ -983,7 +1066,7 @@ impl ChannelMonitor { let (sig, redeemscript) = match self.key_storage { Storage::Local { ref revocation_base_key, .. } => { let redeemscript = if $htlc_idx.is_none() { revokeable_redeemscript.clone() } else { - let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()]; + let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()].0; chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey) }; let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..])); @@ -1009,12 +1092,12 @@ impl ChannelMonitor { if let Some(per_commitment_data) = per_commitment_option { inputs.reserve_exact(per_commitment_data.len()); - for (idx, htlc) in per_commitment_data.iter().enumerate() { + for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); if htlc.transaction_output_index as usize >= tx.output.len() || tx.output[htlc.transaction_output_index as usize].value != htlc.amount_msat / 1000 || tx.output[htlc.transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { - return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); // Corrupted per_commitment_data, fuck this user + return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); // Corrupted per_commitment_data, fuck this user } let input = TxIn { previous_output: BitcoinOutPoint { @@ -1052,7 +1135,7 @@ impl ChannelMonitor { watch_outputs.append(&mut tx.output.clone()); self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); } - if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx + if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); } // Nothing to be done...probably a false positive/local tx let outputs = vec!(TxOut { script_pubkey: self.destination_script.clone(), @@ -1078,6 +1161,23 @@ impl ChannelMonitor { output: spend_tx.output[0].clone(), }); txn_to_broadcast.push(spend_tx); + + if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx { + for htlc_output in ¤t_local_signed_commitment_tx.htlc_outputs { + if let Some(ref source) = htlc_output.3 { + htlc_updated.push((source.clone(), None, htlc_output.0.payment_hash.clone())); + } + } + } + if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx { + for htlc_output in &prev_local_signed_commitment_tx.htlc_outputs { + if let Some(ref source) = htlc_output.3 { + htlc_updated.push((source.clone(), None, htlc_output.0.payment_hash.clone())); + } + } + } + // No need to check remote_claimabe_outpoints, symmetric HTLCSource must be present as per-htlc data on local commitment tx + } else if let Some(per_commitment_data) = per_commitment_option { // While this isn't useful yet, there is a potential race where if a counterparty // revokes a state at the same time as the commitment transaction for that state is @@ -1107,7 +1207,7 @@ impl ChannelMonitor { }, }; let a_htlc_key = match self.their_htlc_base_key { - None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs), + None => return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated), Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)), }; @@ -1138,7 +1238,7 @@ impl ChannelMonitor { { let (sig, redeemscript) = match self.key_storage { Storage::Local { ref htlc_base_key, .. } => { - let htlc = &per_commitment_option.unwrap()[$input.sequence as usize]; + let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0; let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..])); let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key)); @@ -1156,7 +1256,30 @@ impl ChannelMonitor { } } - for (idx, htlc) in per_commitment_data.iter().enumerate() { + macro_rules! sign_input_timeout { + ($sighash_parts: expr, $input: expr, $amount: expr) => { + { + let (sig, redeemscript) = match self.key_storage { + Storage::Local { ref htlc_base_key, .. } => { + let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0; + let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); + let sighash = ignore_error!(Message::from_slice(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..])); + let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key)); + (self.secp_ctx.sign(&sighash, &htlc_key), redeemscript) + }, + Storage::Watchtower { .. } => { + unimplemented!(); + } + }; + $input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec()); + $input.witness[0].push(SigHashType::All as u8); + $input.witness.push(vec![0]); + $input.witness.push(redeemscript.into_bytes()); + } + } + } + + for (idx, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) { let input = TxIn { previous_output: BitcoinOutPoint { @@ -1182,7 +1305,7 @@ impl ChannelMonitor { }), }; let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx); - sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.to_vec()); + sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec()); spendable_outputs.push(SpendableOutputDescriptor::StaticOutput { outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 }, output: single_htlc_tx.output[0].clone(), @@ -1190,9 +1313,32 @@ impl ChannelMonitor { txn_to_broadcast.push(single_htlc_tx); } } + if !htlc.offered { + let input = TxIn { + previous_output: BitcoinOutPoint { + txid: commitment_txid, + vout: htlc.transaction_output_index, + }, + script_sig: Script::new(), + sequence: idx as u32, + witness: Vec::new(), + }; + let mut timeout_tx = Transaction { + version: 2, + lock_time: htlc.cltv_expiry, + input: vec![input], + output: vec!(TxOut { + script_pubkey: self.destination_script.clone(), + value: htlc.amount_msat / 1000, + }), + }; + let sighash_parts = bip143::SighashComponents::new(&timeout_tx); + sign_input_timeout!(sighash_parts, timeout_tx.input[0], htlc.amount_msat / 1000); + txn_to_broadcast.push(timeout_tx); + } } - if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs); } // Nothing to be done...probably a false positive/local tx + if inputs.is_empty() { return (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated); } // Nothing to be done...probably a false positive/local tx let outputs = vec!(TxOut { script_pubkey: self.destination_script.clone(), @@ -1210,7 +1356,7 @@ impl ChannelMonitor { for input in spend_tx.input.iter_mut() { let value = values_drain.next().unwrap(); - sign_input!(sighash_parts, input, value.0, value.1.to_vec()); + sign_input!(sighash_parts, input, value.0, (value.1).0.to_vec()); } spendable_outputs.push(SpendableOutputDescriptor::StaticOutput { @@ -1222,7 +1368,7 @@ impl ChannelMonitor { } } - (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs) + (txn_to_broadcast, (commitment_txid, watch_outputs), spendable_outputs, htlc_updated) } /// Attempst to claim a remote HTLC-Success/HTLC-Timeout s outputs using the revocation key @@ -1311,9 +1457,10 @@ impl ChannelMonitor { } else { (None, None) } } - fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option, delayed_payment_base_key: &Option) -> (Vec, Vec) { + fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx, per_commitment_point: &Option, delayed_payment_base_key: &Option) -> (Vec, Vec, Vec) { let mut res = Vec::with_capacity(local_tx.htlc_outputs.len()); let mut spendable_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); + let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); macro_rules! add_dynamic_output { ($father_tx: expr, $vout: expr) => { @@ -1343,7 +1490,7 @@ impl ChannelMonitor { } } - for &(ref htlc, ref their_sig, ref our_sig) in local_tx.htlc_outputs.iter() { + for &(ref htlc, ref their_sig, ref our_sig, _) in local_tx.htlc_outputs.iter() { if htlc.offered { let mut htlc_timeout_tx = chan_utils::build_htlc_transaction(&local_tx.txid, local_tx.feerate_per_kw, self.their_to_self_delay.unwrap(), htlc, &local_tx.delayed_payment_key, &local_tx.revocation_key); @@ -1370,31 +1517,34 @@ impl ChannelMonitor { htlc_success_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec()); htlc_success_tx.input[0].witness[2].push(SigHashType::All as u8); - htlc_success_tx.input[0].witness.push(payment_preimage.to_vec()); + htlc_success_tx.input[0].witness.push(payment_preimage.0.to_vec()); htlc_success_tx.input[0].witness.push(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_bytes()); add_dynamic_output!(htlc_success_tx, 0); res.push(htlc_success_tx); } } + watch_outputs.push(local_tx.tx.output[htlc.transaction_output_index as usize].clone()); } - (res, spendable_outputs) + (res, spendable_outputs, watch_outputs) } /// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet) /// revoked using data in local_claimable_outpoints. /// Should not be used if check_spend_revoked_transaction succeeds. - fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec, Vec) { + fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec, Vec, (Sha256dHash, Vec)) { let commitment_txid = tx.txid(); if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if local_tx.txid == commitment_txid { match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { - return self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); }, Storage::Watchtower { .. } => { - return self.broadcast_by_local_state(local_tx, &None, &None); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, &None, &None); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); } } } @@ -1403,15 +1553,17 @@ impl ChannelMonitor { if local_tx.txid == commitment_txid { match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref prev_latest_per_commitment_point, .. } => { - return self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key)); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, prev_latest_per_commitment_point, &Some(*delayed_payment_base_key)); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); }, Storage::Watchtower { .. } => { - return self.broadcast_by_local_state(local_tx, &None, &None); + let (local_txn, spendable_outputs, watch_outputs) = self.broadcast_by_local_state(local_tx, &None, &None); + return (local_txn, spendable_outputs, (commitment_txid, watch_outputs)); } } } } - (Vec::new(), Vec::new()) + (Vec::new(), Vec::new(), (commitment_txid, Vec::new())) } /// Generate a spendable output event when closing_transaction get registered onchain. @@ -1456,9 +1608,10 @@ impl ChannelMonitor { } } - fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: &BroadcasterInterface)-> (Vec<(Sha256dHash, Vec)>, Vec) { + fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: &BroadcasterInterface)-> (Vec<(Sha256dHash, Vec)>, Vec, Vec<(HTLCSource, Option, PaymentHash)>) { let mut watch_outputs = Vec::new(); let mut spendable_outputs = Vec::new(); + let mut htlc_updated = Vec::new(); for tx in txn_matched { if tx.input.len() == 1 { // Assuming our keys were not leaked (in which case we're screwed no matter what), @@ -1476,22 +1629,28 @@ impl ChannelMonitor { } }; if funding_txo.is_none() || (prevout.txid == funding_txo.as_ref().unwrap().0.txid && prevout.vout == funding_txo.as_ref().unwrap().0.index as u32) { - let (remote_txn, new_outputs, mut spendable_output) = self.check_spend_remote_transaction(tx, height); + let (remote_txn, new_outputs, mut spendable_output, mut updated) = self.check_spend_remote_transaction(tx, height); txn = remote_txn; spendable_outputs.append(&mut spendable_output); if !new_outputs.1.is_empty() { watch_outputs.push(new_outputs); } if txn.is_empty() { - let (remote_txn, mut outputs) = self.check_spend_local_transaction(tx, height); - spendable_outputs.append(&mut outputs); - txn = remote_txn; + let (local_txn, mut spendable_output, new_outputs) = self.check_spend_local_transaction(tx, height); + spendable_outputs.append(&mut spendable_output); + txn = local_txn; + if !new_outputs.1.is_empty() { + watch_outputs.push(new_outputs); + } } if !funding_txo.is_none() && txn.is_empty() { if let Some(spendable_output) = self.check_spend_closing_transaction(tx) { spendable_outputs.push(spendable_output); } } + if updated.len() > 0 { + htlc_updated.append(&mut updated); + } } else { if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) { let (tx, spendable_output) = self.check_spend_remote_htlc(tx, commitment_number); @@ -1506,6 +1665,10 @@ impl ChannelMonitor { for tx in txn.iter() { broadcaster.broadcast_transaction(tx); } + let mut updated = self.is_resolving_htlc_output(tx); + if updated.len() > 0 { + htlc_updated.append(&mut updated); + } } } if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx { @@ -1513,15 +1676,21 @@ impl ChannelMonitor { broadcaster.broadcast_transaction(&cur_local_tx.tx); match self.key_storage { Storage::Local { ref delayed_payment_base_key, ref latest_per_commitment_point, .. } => { - let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); - spendable_outputs.append(&mut outputs); + let (txs, mut spendable_output, new_outputs) = self.broadcast_by_local_state(&cur_local_tx, latest_per_commitment_point, &Some(*delayed_payment_base_key)); + spendable_outputs.append(&mut spendable_output); + if !new_outputs.is_empty() { + watch_outputs.push((cur_local_tx.txid.clone(), new_outputs)); + } for tx in txs { broadcaster.broadcast_transaction(&tx); } }, Storage::Watchtower { .. } => { - let (txs, mut outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None); - spendable_outputs.append(&mut outputs); + let (txs, mut spendable_output, new_outputs) = self.broadcast_by_local_state(&cur_local_tx, &None, &None); + spendable_outputs.append(&mut spendable_output); + if !new_outputs.is_empty() { + watch_outputs.push((cur_local_tx.txid.clone(), new_outputs)); + } for tx in txs { broadcaster.broadcast_transaction(&tx); } @@ -1530,12 +1699,12 @@ impl ChannelMonitor { } } self.last_block_hash = block_hash.clone(); - (watch_outputs, spendable_outputs) + (watch_outputs, spendable_outputs, htlc_updated) } pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool { if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx { - for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() { + for &(ref htlc, _, _, _) in cur_local_tx.htlc_outputs.iter() { // For inbound HTLCs which we know the preimage for, we have to ensure we hit the // chain with enough room to claim the HTLC without our counterparty being able to // time out the HTLC first. @@ -1564,6 +1733,62 @@ impl ChannelMonitor { } false } + + /// Check if any transaction broadcasted is resolving HTLC output by a success or timeout on a local + /// or remote commitment tx, if so send back the source, preimage if found and payment_hash of resolved HTLC + fn is_resolving_htlc_output(&mut self, tx: &Transaction) -> Vec<(HTLCSource, Option, PaymentHash)> { + let mut htlc_updated = Vec::new(); + + for input in &tx.input { + let mut payment_data: (Option, Option) = (None, None); + if let Some(ref current_local_signed_commitment_tx) = self.current_local_signed_commitment_tx { + if input.previous_output.txid == current_local_signed_commitment_tx.txid { + for htlc_output in ¤t_local_signed_commitment_tx.htlc_outputs { + if input.previous_output.vout == htlc_output.0.transaction_output_index { + payment_data = (htlc_output.3.clone(), Some(htlc_output.0.payment_hash.clone())); + } + } + } + } + if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx { + if input.previous_output.txid == prev_local_signed_commitment_tx.txid { + for htlc_output in &prev_local_signed_commitment_tx.htlc_outputs { + if input.previous_output.vout == htlc_output.0.transaction_output_index { + payment_data = (htlc_output.3.clone(), Some(htlc_output.0.payment_hash.clone())); + } + } + } + } + if let Some(htlc_outputs) = self.remote_claimable_outpoints.get(&input.previous_output.txid) { + for htlc_output in htlc_outputs { + if input.previous_output.vout == htlc_output.0.transaction_output_index { + payment_data = (htlc_output.1.clone(), Some(htlc_output.0.payment_hash.clone())); + } + } + } + // If tx isn't solving htlc output from local/remote commitment tx and htlc isn't outbound we don't need + // to broadcast solving backward + if payment_data.0.is_some() && payment_data.1.is_some() { + let mut payment_preimage = PaymentPreimage([0; 32]); + if (input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33) + || (input.witness.len() == 3 && input.witness[2].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT && input.witness[1].len() == 33) { + log_debug!(self, "Remote used revocation sig to take a {} HTLC output at index {} from commitment_tx {}", if input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT { "offered" } else { "accepted" }, input.previous_output.vout, input.previous_output.txid); + } else if input.witness.len() == 5 && input.witness[4].len() == ACCEPTED_HTLC_SCRIPT_WEIGHT { + payment_preimage.0.copy_from_slice(&tx.input[0].witness[3]); + htlc_updated.push((payment_data.0.unwrap(), Some(payment_preimage), payment_data.1.unwrap())); + } else if input.witness.len() == 3 && input.witness[2].len() == OFFERED_HTLC_SCRIPT_WEIGHT { + payment_preimage.0.copy_from_slice(&tx.input[0].witness[1]); + htlc_updated.push((payment_data.0.unwrap(), Some(payment_preimage), payment_data.1.unwrap())); + } else { + htlc_updated.push((payment_data.0.unwrap(), None, payment_data.1.unwrap())); + } + } else if payment_data.0.is_none() && payment_data.1.is_some() { + log_trace!(self, "Inbound HTLC timeout at {} from {} resolved by {}", input.previous_output.vout, input.previous_output.txid, tx.txid()); + } + } + htlc_updated + } + } const MAX_ALLOC_SIZE: usize = 64*1024; @@ -1659,7 +1884,7 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let offered: bool = Readable::read(reader)?; let amount_msat: u64 = Readable::read(reader)?; let cltv_expiry: u32 = Readable::read(reader)?; - let payment_hash: [u8; 32] = Readable::read(reader)?; + let payment_hash: PaymentHash = Readable::read(reader)?; let transaction_output_index: u32 = Readable::read(reader)?; HTLCOutputInCommitment { @@ -1669,6 +1894,21 @@ impl ReadableArgs> for (Sha256dHash, ChannelM } } + macro_rules! read_htlc_source { + () => { + { + match >::read(reader)? { + 0 => None, + 1 => { + let htlc_source: HTLCSource = Readable::read(reader)?; + Some(htlc_source) + }, + _ => return Err(DecodeError::InvalidValue), + } + } + } + } + let remote_claimable_outpoints_len: u64 = Readable::read(reader)?; let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64)); for _ in 0..remote_claimable_outpoints_len { @@ -1676,7 +1916,9 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let outputs_count: u64 = Readable::read(reader)?; let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..outputs_count { - outputs.push(read_htlc_in_commitment!()); + let out = read_htlc_in_commitment!(); + let source = read_htlc_source!(); + outputs.push((out, source)); } if let Some(_) = remote_claimable_outpoints.insert(txid, outputs) { return Err(DecodeError::InvalidValue); @@ -1701,9 +1943,9 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let remote_hash_commitment_number_len: u64 = Readable::read(reader)?; let mut remote_hash_commitment_number = HashMap::with_capacity(cmp::min(remote_hash_commitment_number_len as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..remote_hash_commitment_number_len { - let txid: [u8; 32] = Readable::read(reader)?; + let payment_hash: PaymentHash = Readable::read(reader)?; let commitment_number = >::read(reader)?.0; - if let Some(_) = remote_hash_commitment_number.insert(txid, commitment_number) { + if let Some(_) = remote_hash_commitment_number.insert(payment_hash, commitment_number) { return Err(DecodeError::InvalidValue); } } @@ -1733,7 +1975,10 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let htlc_outputs_len: u64 = Readable::read(reader)?; let mut htlc_outputs = Vec::with_capacity(cmp::min(htlc_outputs_len as usize, MAX_ALLOC_SIZE / 128)); for _ in 0..htlc_outputs_len { - htlc_outputs.push((read_htlc_in_commitment!(), Readable::read(reader)?, Readable::read(reader)?)); + let out = read_htlc_in_commitment!(); + let sigs = (Readable::read(reader)?, Readable::read(reader)?); + let source = read_htlc_source!(); + htlc_outputs.push((out, sigs.0, sigs.1, source)); } LocalSignedTx { @@ -1766,11 +2011,11 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32)); let mut sha = Sha256::new(); for _ in 0..payment_preimages_len { - let preimage: [u8; 32] = Readable::read(reader)?; + let preimage: PaymentPreimage = Readable::read(reader)?; sha.reset(); - sha.input(&preimage); - let mut hash = [0; 32]; - sha.result(&mut hash); + sha.input(&preimage.0[..]); + let mut hash = PaymentHash([0; 32]); + sha.result(&mut hash.0[..]); if let Some(_) = payment_preimages.insert(hash, preimage) { return Err(DecodeError::InvalidValue); } @@ -1816,6 +2061,7 @@ mod tests { use bitcoin::blockdata::transaction::Transaction; use crypto::digest::Digest; use hex; + use ln::channelmanager::{PaymentPreimage, PaymentHash}; use ln::channelmonitor::ChannelMonitor; use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys}; use util::sha2::Sha256; @@ -2207,12 +2453,12 @@ mod tests { { let mut rng = thread_rng(); for _ in 0..20 { - let mut preimage = [0; 32]; - rng.fill_bytes(&mut preimage); + let mut preimage = PaymentPreimage([0; 32]); + rng.fill_bytes(&mut preimage.0[..]); let mut sha = Sha256::new(); - sha.input(&preimage); - let mut hash = [0; 32]; - sha.result(&mut hash); + sha.input(&preimage.0[..]); + let mut hash = PaymentHash([0; 32]); + sha.result(&mut hash.0[..]); preimages.push((preimage, hash)); } } @@ -2222,13 +2468,13 @@ mod tests { { let mut res = Vec::new(); for (idx, preimage) in $preimages_slice.iter().enumerate() { - res.push(HTLCOutputInCommitment { + res.push((HTLCOutputInCommitment { offered: true, amount_msat: 0, cltv_expiry: 0, payment_hash: preimage.1.clone(), transaction_output_index: idx as u32, - }); + }, None)); } res } @@ -2238,7 +2484,7 @@ mod tests { ($preimages_slice: expr) => { { let mut inp = preimages_slice_to_htlc_outputs!($preimages_slice); - let res: Vec<_> = inp.drain(..).map(|e| { (e, dummy_sig.clone(), dummy_sig.clone()) }).collect(); + let res: Vec<_> = inp.drain(..).map(|e| { (e.0, dummy_sig.clone(), dummy_sig.clone(), e.1) }).collect(); res } } diff --git a/src/ln/msgs.rs b/src/ln/msgs.rs index 354376649c7..4cff6256f83 100644 --- a/src/ln/msgs.rs +++ b/src/ln/msgs.rs @@ -29,6 +29,8 @@ use std::result::Result; use util::{byte_utils, events}; use util::ser::{Readable, Writeable, Writer}; +use ln::channelmanager::{PaymentPreimage, PaymentHash}; + /// An error in decoding a message or struct. #[derive(Debug)] pub enum DecodeError { @@ -256,7 +258,7 @@ pub struct UpdateAddHTLC { pub(crate) channel_id: [u8; 32], pub(crate) htlc_id: u64, pub(crate) amount_msat: u64, - pub(crate) payment_hash: [u8; 32], + pub(crate) payment_hash: PaymentHash, pub(crate) cltv_expiry: u32, pub(crate) onion_routing_packet: OnionPacket, } @@ -266,7 +268,7 @@ pub struct UpdateAddHTLC { pub struct UpdateFulfillHTLC { pub(crate) channel_id: [u8; 32], pub(crate) htlc_id: u64, - pub(crate) payment_preimage: [u8; 32], + pub(crate) payment_preimage: PaymentPreimage, } /// An update_fail_htlc message to be sent or received from a peer diff --git a/src/ln/router.rs b/src/ln/router.rs index 3de73ccc059..3920d44fc7a 100644 --- a/src/ln/router.rs +++ b/src/ln/router.rs @@ -25,7 +25,7 @@ use std::collections::btree_map::Entry as BtreeEntry; use std; /// A hop in a route -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct RouteHop { /// The node_id of the node at this hop. pub pubkey: PublicKey, @@ -39,7 +39,7 @@ pub struct RouteHop { } /// A route from us through the network to a destination -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub struct Route { /// The list of hops, NOT INCLUDING our own, where the last hop is the destination. Thus, this /// must always be at least length one. By protocol rules, this may not currently exceed 20 in diff --git a/src/util/events.rs b/src/util/events.rs index a113217943f..2d810e839ab 100644 --- a/src/util/events.rs +++ b/src/util/events.rs @@ -13,6 +13,7 @@ //TODO: We need better separation of event types ^ use ln::msgs; +use ln::channelmanager::{PaymentPreimage, PaymentHash}; use chain::transaction::OutPoint; use chain::keysinterface::SpendableOutputDescriptor; @@ -59,7 +60,7 @@ pub enum Event { /// the amount expected. PaymentReceived { /// The hash for which the preimage should be handed to the ChannelManager. - payment_hash: [u8; 32], + payment_hash: PaymentHash, /// The value, in thousandths of a satoshi, that this payment is for. amt: u64, }, @@ -71,7 +72,7 @@ pub enum Event { /// The preimage to the hash given to ChannelManager::send_payment. /// Note that this serves as a payment receipt, if you wish to have such a thing, you must /// store it somehow! - payment_preimage: [u8; 32], + payment_preimage: PaymentPreimage, }, /// Indicates an outbound payment we made failed. Probably some intermediary node dropped /// something. You may wish to retry with a different route. @@ -79,7 +80,7 @@ pub enum Event { /// deduplicate them by payment_hash (which MUST be unique)! PaymentFailed { /// The hash which was given to ChannelManager::send_payment. - payment_hash: [u8; 32], + payment_hash: PaymentHash, /// Indicates the payment was rejected for some reason by the recipient. This implies that /// the payment has failed, not just the route in question. If this is not set, you may /// retry the payment via a different route. diff --git a/src/util/ser.rs b/src/util/ser.rs index 84cfa8d1633..c1d2802a76d 100644 --- a/src/util/ser.rs +++ b/src/util/ser.rs @@ -12,6 +12,7 @@ use bitcoin::util::hash::Sha256dHash; use bitcoin::blockdata::script::Script; use std::marker::Sized; use ln::msgs::DecodeError; +use ln::channelmanager::{PaymentPreimage, PaymentHash}; use util::byte_utils; use util::byte_utils::{be64_to_array, be48_to_array, be32_to_array, be16_to_array, slice_to_be16, slice_to_be32, slice_to_be48, slice_to_be64}; @@ -386,3 +387,29 @@ impl Readable for Signature { } } } + +impl Writeable for PaymentPreimage { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + self.0.write(w) + } +} + +impl Readable for PaymentPreimage { + fn read(r: &mut R) -> Result { + let buf: [u8; 32] = Readable::read(r)?; + Ok(PaymentPreimage(buf)) + } +} + +impl Writeable for PaymentHash { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + self.0.write(w) + } +} + +impl Readable for PaymentHash { + fn read(r: &mut R) -> Result { + let buf: [u8; 32] = Readable::read(r)?; + Ok(PaymentHash(buf)) + } +} diff --git a/src/util/test_utils.rs b/src/util/test_utils.rs index 33fb63b5c3d..4cd4f4406b1 100644 --- a/src/util/test_utils.rs +++ b/src/util/test_utils.rs @@ -4,6 +4,7 @@ use chain::transaction::OutPoint; use ln::channelmonitor; use ln::msgs; use ln::msgs::{HandleError}; +use ln::channelmonitor::HTLCUpdate; use util::events; use util::logger::{Logger, Level, Record}; use util::ser::{ReadableArgs, Writer}; @@ -64,6 +65,10 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { assert!(self.simple_monitor.add_update_monitor(funding_txo, monitor).is_ok()); self.update_ret.lock().unwrap().clone() } + + fn fetch_pending_htlc_updated(&self) -> Vec { + return self.simple_monitor.fetch_pending_htlc_updated(); + } } pub struct TestBroadcaster {