From 2d8afeccdb4f5aa6232e6d87c6096e980b836072 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Tue, 24 Apr 2018 00:19:52 -0400 Subject: [PATCH] Rewrite channelmonitor framework and implement a bunch of it --- fuzz/fuzz_targets/full_stack_target.rs | 4 +- src/ln/chan_utils.rs | 36 +- src/ln/channel.rs | 231 ++++---- src/ln/channelmanager.rs | 545 +++++++++++++---- src/ln/channelmonitor.rs | 785 +++++++++++++++++-------- src/util/test_utils.rs | 3 +- 6 files changed, 1157 insertions(+), 447 deletions(-) diff --git a/fuzz/fuzz_targets/full_stack_target.rs b/fuzz/fuzz_targets/full_stack_target.rs index e36f6420..4ae9be41 100644 --- a/fuzz/fuzz_targets/full_stack_target.rs +++ b/fuzz/fuzz_targets/full_stack_target.rs @@ -15,7 +15,7 @@ use crypto::sha2::Sha256; use crypto::digest::Digest; use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil}; -use lightning::ln::{channelmonitor,msgs}; +use lightning::ln::channelmonitor; use lightning::ln::channelmanager::ChannelManager; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; use lightning::ln::router::Router; @@ -93,7 +93,7 @@ impl FeeEstimator for FuzzEstimator { struct TestChannelMonitor {} impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { - fn add_update_monitor(&self, _funding_txo: (Sha256dHash, u16), _monitor: channelmonitor::ChannelMonitor) -> Result<(), msgs::HandleError> { + fn add_update_monitor(&self, _funding_txo: (Sha256dHash, u16), _monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { //TODO! Ok(()) } diff --git a/src/ln/chan_utils.rs b/src/ln/chan_utils.rs index 81fa29f5..45f67437 100644 --- a/src/ln/chan_utils.rs +++ b/src/ln/chan_utils.rs @@ -1,6 +1,7 @@ use bitcoin::blockdata::script::{Script,Builder}; use bitcoin::blockdata::opcodes; -use bitcoin::util::hash::Hash160; +use bitcoin::blockdata::transaction::{TxIn,TxOut,Transaction}; +use bitcoin::util::hash::{Hash160,Sha256dHash}; use secp256k1::key::{PublicKey,SecretKey}; use secp256k1::Secp256k1; @@ -11,6 +12,9 @@ use crypto::ripemd160::Ripemd160; use util::sha2::Sha256; +pub const HTLC_SUCCESS_TX_WEIGHT: u64 = 703; +pub const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663; + // Various functions for key derivation and transaction creation for use within channels. Primarily // used in Channel and ChannelMonitor. @@ -233,3 +237,33 @@ pub fn get_htlc_redeemscript_with_explicit_keys(htlc: &HTLCOutputInCommitment, a pub fn get_htlc_redeemscript(htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Script { get_htlc_redeemscript_with_explicit_keys(htlc, &keys.a_htlc_key, &keys.b_htlc_key, &keys.revocation_key) } + +pub fn build_htlc_transaction(prev_hash: &Sha256dHash, feerate_per_kw: u64, to_self_delay: u16, htlc: &HTLCOutputInCommitment, a_delayed_payment_key: &PublicKey, revocation_key: &PublicKey) -> Transaction { + let mut txins: Vec = Vec::new(); + txins.push(TxIn { + prev_hash: prev_hash.clone(), + prev_index: htlc.transaction_output_index, + script_sig: Script::new(), + sequence: 0, + witness: Vec::new(), + }); + + let total_fee = if htlc.offered { + feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000 + } else { + feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000 + }; + + let mut txouts: Vec = Vec::new(); + txouts.push(TxOut { + script_pubkey: get_revokeable_redeemscript(revocation_key, to_self_delay, a_delayed_payment_key).to_v0_p2wsh(), + value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here) + }); + + Transaction { + version: 2, + lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 }, + input: txins, + output: txouts, + } +} diff --git a/src/ln/channel.rs b/src/ln/channel.rs index fcdb9fcb..f16de61a 100644 --- a/src/ln/channel.rs +++ b/src/ln/channel.rs @@ -18,7 +18,7 @@ use ln::msgs; use ln::msgs::{HandleError, MsgEncodable}; use ln::channelmonitor::ChannelMonitor; use ln::channelmanager::{PendingForwardHTLCInfo, HTLCFailReason}; -use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment}; +use ln::chan_utils::{TxCreationKeys,HTLCOutputInCommitment,HTLC_SUCCESS_TX_WEIGHT,HTLC_TIMEOUT_TX_WEIGHT}; use ln::chan_utils; use chain::chaininterface::{FeeEstimator,ConfirmationTarget}; use util::{transaction_utils,rng}; @@ -254,6 +254,12 @@ pub struct Channel { channel_update_count: u32, feerate_per_kw: u64, + #[cfg(test)] + // Used in ChannelManager's tests to send a revoked transaction + pub last_local_commitment_txn: Vec, + #[cfg(not(test))] + last_local_commitment_txn: Vec, + last_sent_closing_fee: Option<(u64, u64)>, // (feerate, fee) /// The hash of the block in which the funding transaction reached our CONF_TARGET. We use this @@ -307,8 +313,6 @@ const BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 7; //TODO? const MAX_LOCAL_BREAKDOWN_TIMEOUT: u16 = 6 * 24 * 14; const COMMITMENT_TX_BASE_WEIGHT: u64 = 724; const COMMITMENT_TX_WEIGHT_PER_HTLC: u64 = 172; -const HTLC_SUCCESS_TX_WEIGHT: u64 = 703; -const HTLC_TIMEOUT_TX_WEIGHT: u64 = 663; const SPENDING_INPUT_FOR_A_OUTPUT_WEIGHT: u64 = 79; // prevout: 36, nSequence: 4, script len: 1, witness lengths: (3+1)/4, sig: 73/4, if-selector: 1, redeemScript: (6 ops + 2*33 pubkeys + 1*2 delay)/4 const B_OUTPUT_PLUS_SPENDING_INPUT_WEIGHT: u64 = 104; // prevout: 40, nSequence: 4, script len: 1, witness lengths: 3/4, sig: 73/4, pubkey: 33/4, output: 31 (TODO: Wrong? Useless?) @@ -362,7 +366,7 @@ impl Channel { let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script(); let channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key).unwrap(), - &PublicKey::from_secret_key(&secp_ctx, &chan_keys.htlc_base_key).unwrap(), + &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script); Channel { @@ -385,6 +389,8 @@ impl Channel { next_remote_htlc_id: 0, channel_update_count: 0, + last_local_commitment_txn: Vec::new(), + last_sent_closing_fee: None, funding_tx_confirmed_in: Default::default(), @@ -477,9 +483,10 @@ impl Channel { let our_channel_monitor_claim_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script(); let mut channel_monitor = ChannelMonitor::new(&chan_keys.revocation_base_key, &PublicKey::from_secret_key(&secp_ctx, &chan_keys.delayed_payment_base_key).unwrap(), - &PublicKey::from_secret_key(&secp_ctx, &chan_keys.htlc_base_key).unwrap(), + &chan_keys.htlc_base_key, BREAKDOWN_TIMEOUT, our_channel_monitor_claim_script); channel_monitor.set_their_htlc_base_key(&msg.htlc_basepoint); + channel_monitor.set_their_to_self_delay(msg.to_self_delay); let mut chan = Channel { user_id: user_id, @@ -500,6 +507,8 @@ impl Channel { next_remote_htlc_id: 0, channel_update_count: 0, + last_local_commitment_txn: Vec::new(), + last_sent_closing_fee: None, funding_tx_confirmed_in: Default::default(), @@ -855,40 +864,25 @@ impl Channel { /// @local is used only to convert relevant internal structures which refer to remote vs local /// to decide value of outputs and direction of HTLCs. fn build_htlc_transaction(&self, prev_hash: &Sha256dHash, htlc: &HTLCOutputInCommitment, local: bool, keys: &TxCreationKeys) -> Transaction { - let mut txins: Vec = Vec::new(); - txins.push(TxIn { - prev_hash: prev_hash.clone(), - prev_index: htlc.transaction_output_index, - script_sig: Script::new(), - sequence: 0, - witness: Vec::new(), - }); + chan_utils::build_htlc_transaction(prev_hash, self.feerate_per_kw, if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT }, htlc, &keys.a_delayed_payment_key, &keys.revocation_key) + } - let total_fee = if htlc.offered { - self.feerate_per_kw * HTLC_TIMEOUT_TX_WEIGHT / 1000 - } else { - self.feerate_per_kw * HTLC_SUCCESS_TX_WEIGHT / 1000 - }; + fn create_htlc_tx_signature(&self, tx: &Transaction, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result<(Script, Signature, bool), HandleError> { + if tx.input.len() != 1 { + panic!("Tried to sign HTLC transaction that had input count != 1!"); + } - let mut txouts: Vec = Vec::new(); - txouts.push(TxOut { - script_pubkey: chan_utils::get_revokeable_redeemscript(&keys.revocation_key, - if local { self.their_to_self_delay } else { BREAKDOWN_TIMEOUT }, - &keys.a_delayed_payment_key).to_v0_p2wsh(), - value: htlc.amount_msat / 1000 - total_fee //TODO: BOLT 3 does not specify if we should add amount_msat before dividing or if we should divide by 1000 before subtracting (as we do here) - }); + let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys); - Transaction { - version: 2, - lock_time: if htlc.offered { htlc.cltv_expiry } else { 0 }, - input: txins, - output: txouts, - } + let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key)); + let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap(); + let is_local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).unwrap() == keys.a_htlc_key; + Ok((htlc_redeemscript, self.secp_ctx.sign(&sighash, &our_htlc_key).unwrap(), is_local_tx)) } /// 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<(), HandleError> { + fn sign_htlc_transaction(&self, tx: &mut Transaction, their_sig: &Signature, preimage: &Option<[u8; 32]>, htlc: &HTLCOutputInCommitment, keys: &TxCreationKeys) -> Result { if tx.input.len() != 1 { panic!("Tried to sign HTLC transaction that had input count != 1!"); } @@ -896,13 +890,7 @@ impl Channel { panic!("Tried to re-sign HTLC transaction"); } - let htlc_redeemscript = chan_utils::get_htlc_redeemscript(&htlc, &keys); - - let our_htlc_key = secp_derived_key!(chan_utils::derive_private_key(&self.secp_ctx, &keys.per_commitment_point, &self.local_keys.htlc_base_key)); - let sighash = Message::from_slice(&bip143::SighashComponents::new(&tx).sighash_all(&tx.input[0], &htlc_redeemscript, htlc.amount_msat / 1000)[..]).unwrap(); - let our_sig = self.secp_ctx.sign(&sighash, &our_htlc_key).unwrap(); - - let local_tx = PublicKey::from_secret_key(&self.secp_ctx, &our_htlc_key).unwrap() == keys.a_htlc_key; + let (htlc_redeemscript, our_sig, local_tx) = self.create_htlc_tx_signature(tx, htlc, keys)?; tx.input[0].witness.push(Vec::new()); // First is the multisig dummy @@ -924,10 +912,10 @@ impl Channel { tx.input[0].witness.push(htlc_redeemscript.into_vec()); - Ok(()) + Ok(our_sig) } - pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result, HandleError> { + pub fn get_update_fulfill_htlc(&mut self, payment_preimage_arg: [u8; 32]) -> Result, HandleError> { // 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, @@ -989,19 +977,21 @@ impl Channel { if htlc_amount_msat == 0 { return Err(HandleError{err: "Unable to find a pending HTLC which matched the given payment preimage", msg: None}); } - self.channel_monitor.provide_payment_preimage(&payment_preimage_arg); + self.channel_monitor.provide_payment_preimage(&payment_hash_calc, &payment_preimage_arg); - Ok(Some(msgs::UpdateFulfillHTLC { + Ok(Some((msgs::UpdateFulfillHTLC { channel_id: self.channel_id(), htlc_id: htlc_id, payment_preimage: payment_preimage_arg, - })) + }, self.channel_monitor.clone()))) } - pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result, HandleError> { + pub fn get_update_fulfill_htlc_and_commit(&mut self, payment_preimage: [u8; 32]) -> Result, HandleError> { match self.get_update_fulfill_htlc(payment_preimage)? { - Some(update_fulfill_htlc) => - Ok(Some((update_fulfill_htlc, self.send_commitment_no_status_check()?))), + Some(update_fulfill_htlc) => { + let (commitment, monitor_update) = self.send_commitment_no_status_check()?; + Ok(Some((update_fulfill_htlc.0, commitment, monitor_update))) + }, None => Ok(None) } } @@ -1067,10 +1057,12 @@ impl Channel { })) } - pub fn get_update_fail_htlc_and_commit(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result, HandleError> { + pub fn get_update_fail_htlc_and_commit(&mut self, payment_hash: &[u8; 32], err_packet: msgs::OnionErrorPacket) -> Result, HandleError> { match self.get_update_fail_htlc(payment_hash, err_packet)? { - Some(update_fail_htlc) => - Ok(Some((update_fail_htlc, self.send_commitment_no_status_check()?))), + Some(update_fail_htlc) => { + let (commitment, monitor_update) = self.send_commitment_no_status_check()?; + Ok(Some((update_fail_htlc, commitment, monitor_update))) + }, None => Ok(None) } } @@ -1122,6 +1114,7 @@ impl Channel { let obscure_factor = self.get_commitment_transaction_number_obscure_factor(); self.channel_monitor.set_commitment_obscure_factor(obscure_factor); + self.channel_monitor.set_their_to_self_delay(msg.to_self_delay); self.channel_state = ChannelState::OurInitSent as u32 | ChannelState::TheirInitSent as u32; @@ -1146,7 +1139,7 @@ impl Channel { Ok((remote_initial_commitment_tx, self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap())) } - pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result { + pub fn funding_created(&mut self, msg: &msgs::FundingCreated) -> Result<(msgs::FundingSigned, ChannelMonitor), HandleError> { if self.channel_outbound { return Err(HandleError{err: "Received funding_created for an outbound channel?", msg: None}); } @@ -1160,7 +1153,7 @@ impl Channel { self.channel_monitor.set_funding_info(msg.funding_txid, msg.funding_output_index); let (remote_initial_commitment_tx, our_signature) = match self.funding_created_signature(&msg.signature) { - Ok((remote_initial_commitment_tx, sig)) => (remote_initial_commitment_tx, sig), + Ok(res) => res, Err(e) => { self.channel_monitor.unset_funding_info(); return Err(e); @@ -1169,24 +1162,22 @@ impl Channel { // Now that we're past error-generating stuff, update our local state: - //TODO: Determine which tx index in remote_initial_commitment_transaction's outputs - //represent a revokeable script! - self.channel_monitor.provide_tx_info(&remote_initial_commitment_tx, 0, Vec::new()); + self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_initial_commitment_tx, Vec::new()); self.channel_state = ChannelState::FundingSent as u32; let funding_txo = self.channel_monitor.get_funding_txo().unwrap(); self.channel_id = funding_txo.0.into_be() ^ Uint256::from_u64(funding_txo.1 as u64).unwrap(); //TODO: or le? self.cur_remote_commitment_transaction_number -= 1; self.cur_local_commitment_transaction_number -= 1; - Ok(msgs::FundingSigned { + Ok((msgs::FundingSigned { channel_id: self.channel_id, signature: our_signature - }) + }, self.channel_monitor.clone())) } /// Handles a funding_signed message from the remote end. /// If this call is successful, broadcast the funding transaction (and not before!) - pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result<(), HandleError> { + pub fn funding_signed(&mut self, msg: &msgs::FundingSigned) -> Result { if !self.channel_outbound { return Err(HandleError{err: "Received funding_signed for an inbound channel?", msg: None}); } @@ -1200,16 +1191,19 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; - let local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0; + let mut local_initial_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false).0; let local_sighash = Message::from_slice(&bip143::SighashComponents::new(&local_initial_commitment_tx).sighash_all(&local_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap(); // They sign the "local" commitment transaction, allowing us to broadcast the tx if we wish. secp_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid funding_signed signature from peer"); + self.sign_commitment_transaction(&mut local_initial_commitment_tx, &msg.signature); + self.channel_monitor.provide_latest_local_commitment_tx_info(local_initial_commitment_tx.clone(), local_keys, self.feerate_per_kw, Vec::new()); + self.last_local_commitment_txn = vec![local_initial_commitment_tx]; self.channel_state = ChannelState::FundingSent as u32; self.cur_local_commitment_transaction_number -= 1; - Ok(()) + Ok(self.channel_monitor.clone()) } pub fn funding_locked(&mut self, msg: &msgs::FundingLocked) -> Result<(), HandleError> { @@ -1342,7 +1336,7 @@ impl Channel { Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: None}) } - pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result<(), HandleError> { + pub fn update_fulfill_htlc(&mut self, msg: &msgs::UpdateFulfillHTLC) -> Result { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None}); } @@ -1352,9 +1346,9 @@ impl Channel { let mut payment_hash = [0; 32]; sha.result(&mut payment_hash); - self.channel_monitor.provide_payment_preimage(&msg.payment_preimage); + self.channel_monitor.provide_payment_preimage(&payment_hash, &msg.payment_preimage); self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?; - Ok(()) + Ok(self.channel_monitor.clone()) } pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> { @@ -1374,7 +1368,7 @@ impl Channel { Ok(()) } - pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option), HandleError> { + pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option, ChannelMonitor), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got commitment signed message when channel was not in an operational state", msg: None}); } @@ -1382,7 +1376,7 @@ impl Channel { let funding_script = self.get_funding_redeemscript(); let local_keys = self.build_local_transaction_keys(self.cur_local_commitment_transaction_number)?; - let local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false); + let mut local_commitment_tx = self.build_commitment_transaction(self.cur_local_commitment_transaction_number, &local_keys, true, false); 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_call!(self.secp_ctx.verify(&local_sighash, &msg.signature, &self.their_funding_pubkey), "Invalid commitment tx signature from peer"); @@ -1391,17 +1385,31 @@ impl Channel { return Err(HandleError{err: "Got wrong number of HTLC signatures from remote", msg: None}); } + let mut new_local_commitment_txn = Vec::with_capacity(local_commitment_tx.1.len() + 1); + self.sign_commitment_transaction(&mut local_commitment_tx.0, &msg.signature); + 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 htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys); + let mut htlc_tx = self.build_htlc_transaction(&local_commitment_txid, htlc, true, &local_keys); 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_call!(self.secp_ctx.verify(&htlc_sighash, &msg.htlc_signatures[idx], &local_keys.b_htlc_key), "Invalid HTLC tx siganture 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)?; + new_local_commitment_txn.push(htlc_tx); + htlc_sig + } else { + self.create_htlc_tx_signature(&htlc_tx, htlc, &local_keys)?.1 + }; + htlcs_and_sigs.push(((*htlc).clone(), msg.htlc_signatures[idx], htlc_sig)); } let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &self.build_local_commitment_secret(self.cur_local_commitment_transaction_number - 1)).unwrap(); let per_commitment_secret = chan_utils::build_commitment_secret(self.local_keys.commitment_seed, self.cur_local_commitment_transaction_number + 1); // Update state now that we've passed all the can-fail calls... + self.channel_monitor.provide_latest_local_commitment_tx_info(local_commitment_tx.0, local_keys, self.feerate_per_kw, htlcs_and_sigs); let mut need_our_commitment = false; for htlc in self.pending_htlcs.iter_mut() { @@ -1425,24 +1433,26 @@ impl Channel { self.value_to_self_msat += claimed_value_msat; self.cur_local_commitment_transaction_number -= 1; + self.last_local_commitment_txn = new_local_commitment_txn; - let our_commitment_signed = if need_our_commitment && (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 { + let (our_commitment_signed, monitor_update) = if need_our_commitment && (self.channel_state & (ChannelState::AwaitingRemoteRevoke as u32)) == 0 { // If we're AwaitingRemoteRevoke we can't send a new commitment here, but that's ok - // we'll send one right away when we get the revoke_and_ack when we // free_holding_cell_htlcs(). - Some(self.send_commitment_no_status_check()?) - } else { None }; + let (msg, monitor) = self.send_commitment_no_status_check()?; + (Some(msg), monitor) + } else { (None, self.channel_monitor.clone()) }; Ok((msgs::RevokeAndACK { channel_id: self.channel_id, per_commitment_secret: per_commitment_secret, next_per_commitment_point: next_per_commitment_point, - }, our_commitment_signed)) + }, our_commitment_signed, monitor_update)) } /// Used to fulfill holding_cell_htlcs when we get a remote ack (or implicitly get it by them /// fulfilling or failing the last pending HTLC) - fn free_holding_cell_htlcs(&mut self) -> Result, HandleError> { + fn free_holding_cell_htlcs(&mut self) -> Result, HandleError> { if self.holding_cell_htlc_updates.len() != 0 { let mut htlc_updates = Vec::new(); mem::swap(&mut htlc_updates, &mut self.holding_cell_htlc_updates); @@ -1470,7 +1480,7 @@ impl Channel { }, &HTLCUpdateAwaitingACK::ClaimHTLC { payment_preimage, .. } => { match self.get_update_fulfill_htlc(payment_preimage) { - Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap()), + Ok(update_fulfill_msg_option) => update_fulfill_htlcs.push(update_fulfill_msg_option.unwrap().0), Err(e) => { err = Some(e); } @@ -1494,12 +1504,13 @@ impl Channel { //fail it back the route, if its a temporary issue we can ignore it... match err { None => { - Ok(Some(msgs::CommitmentUpdate { + let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?; + Ok(Some((msgs::CommitmentUpdate { update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, - commitment_signed: self.send_commitment_no_status_check()? - })) + commitment_signed, + }, monitor_update))) }, Some(e) => Err(e) } @@ -1513,7 +1524,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) -> Result<(Option, Vec, Vec<([u8; 32], HTLCFailReason)>), HandleError> { + pub fn revoke_and_ack(&mut self, msg: &msgs::RevokeAndACK) -> Result<(Option, Vec, Vec<([u8; 32], HTLCFailReason)>, ChannelMonitor), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Got revoke/ACK message when channel was not in an operational state", msg: None}); } @@ -1522,7 +1533,7 @@ impl Channel { return Err(HandleError{err: "Got a revoke commitment secret which didn't correspond to their current pubkey", msg: None}); } } - self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret)?; + self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret, Some((self.cur_remote_commitment_transaction_number - 1, msg.next_per_commitment_point)))?; // Update state now that we've passed all the can-fail calls... // (note that we may still fail to generate the new commitment_signed message, but that's @@ -1572,18 +1583,19 @@ impl Channel { match self.free_holding_cell_htlcs()? { Some(commitment_update) => { - Ok((Some(commitment_update), to_forward_infos, revoked_htlcs)) + Ok((Some(commitment_update.0), to_forward_infos, revoked_htlcs, commitment_update.1)) }, None => { if require_commitment { + let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?; Ok((Some(msgs::CommitmentUpdate { update_add_htlcs: Vec::new(), update_fulfill_htlcs: Vec::new(), update_fail_htlcs: Vec::new(), - commitment_signed: self.send_commitment_no_status_check()? - }), to_forward_infos, revoked_htlcs)) + commitment_signed + }), to_forward_infos, revoked_htlcs, monitor_update)) } else { - Ok((None, to_forward_infos, revoked_htlcs)) + Ok((None, to_forward_infos, revoked_htlcs, self.channel_monitor.clone())) } } } @@ -1789,6 +1801,13 @@ impl Channel { self.user_id } + pub fn channel_monitor(&self) -> ChannelMonitor { + if self.channel_state < ChannelState::FundingCreated as u32 { + panic!("Can't get a channel monitor until funding has been created"); + } + self.channel_monitor.clone() + } + /// Guaranteed to be Some after both FundingLocked messages have been exchanged (and, thus, /// is_usable() returns true). pub fn get_short_channel_id(&self) -> Option { @@ -1837,13 +1856,6 @@ impl Channel { res as u32 } - pub fn channel_monitor(&self) -> ChannelMonitor { - if self.channel_state < ChannelState::FundingCreated as u32 { - panic!("Can't get a channel monitor until funding has been created"); - } - self.channel_monitor.clone() - } - /// Returns true if this channel is fully established and not known to be closing. pub fn is_usable(&self) -> bool { let mask = ChannelState::ChannelFunded as u32 | BOTH_SIDES_SHUTDOWN_MASK; @@ -2006,7 +2018,7 @@ impl Channel { }) } - fn get_outbound_funding_created_signature(&mut self) -> Result { + fn get_outbound_funding_created_signature(&mut self) -> Result<(Signature, Transaction), HandleError> { let funding_script = self.get_funding_redeemscript(); let remote_keys = self.build_remote_transaction_keys()?; @@ -2014,7 +2026,7 @@ impl Channel { let remote_sighash = Message::from_slice(&bip143::SighashComponents::new(&remote_initial_commitment_tx).sighash_all(&remote_initial_commitment_tx.input[0], &funding_script, self.channel_value_satoshis)[..]).unwrap(); // We sign the "remote" commitment transaction, allowing them to broadcast the tx if they wish. - Ok(self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap()) + Ok((self.secp_ctx.sign(&remote_sighash, &self.local_keys.funding_key).unwrap(), remote_initial_commitment_tx)) } /// Updates channel state with knowledge of the funding transaction's txid/index, and generates @@ -2023,7 +2035,7 @@ impl Channel { /// or if called on an inbound channel. /// Note that channel_id changes during this call! /// Do NOT broadcast the funding transaction until after a successful funding_signed call! - pub fn get_outbound_funding_created(&mut self, funding_txid: Sha256dHash, funding_output_index: u16) -> Result { + pub fn get_outbound_funding_created(&mut self, funding_txid: Sha256dHash, funding_output_index: u16) -> Result<(msgs::FundingCreated, ChannelMonitor), HandleError> { if !self.channel_outbound { panic!("Tried to create outbound funding_created message on an inbound channel!"); } @@ -2036,8 +2048,8 @@ impl Channel { self.channel_monitor.set_funding_info(funding_txid, funding_output_index); - let our_signature = match self.get_outbound_funding_created_signature() { - Ok(sig) => sig, + let (our_signature, commitment_tx) = match self.get_outbound_funding_created_signature() { + Ok(res) => res, Err(e) => { self.channel_monitor.unset_funding_info(); return Err(e); @@ -2047,18 +2059,18 @@ impl Channel { let temporary_channel_id = self.channel_id; // Now that we're past error-generating stuff, update our local state: - + self.channel_monitor.provide_latest_remote_commitment_tx_info(&commitment_tx, Vec::new()); self.channel_state = ChannelState::FundingCreated as u32; let funding_txo = self.channel_monitor.get_funding_txo().unwrap(); self.channel_id = funding_txo.0.into_be() ^ Uint256::from_u64(funding_txo.1 as u64).unwrap(); //TODO: or le? self.cur_remote_commitment_transaction_number -= 1; - Ok(msgs::FundingCreated { + Ok((msgs::FundingCreated { temporary_channel_id: temporary_channel_id, funding_txid: funding_txid, funding_output_index: funding_output_index, signature: our_signature - }) + }, self.channel_monitor.clone())) } /// Gets an UnsignedChannelAnnouncement, as well as a signature covering it using our @@ -2170,7 +2182,7 @@ impl Channel { } /// Creates a signed commitment transaction to send to the remote peer. - pub fn send_commitment(&mut self) -> Result { + pub fn send_commitment(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> { if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) { return Err(HandleError{err: "Cannot create commitment tx until channel is fully established", msg: None}); } @@ -2190,7 +2202,7 @@ impl Channel { self.send_commitment_no_status_check() } /// Only fails in case of bad keys - fn send_commitment_no_status_check(&mut self) -> Result { + fn send_commitment_no_status_check(&mut self) -> Result<(msgs::CommitmentSigned, ChannelMonitor), HandleError> { let funding_script = self.get_funding_redeemscript(); // We can upgrade the status of some HTLCs that are waiting on a commitment, even if we @@ -2221,23 +2233,26 @@ impl Channel { } // Update state now that we've passed all the can-fail calls... + self.channel_monitor.provide_latest_remote_commitment_tx_info(&remote_commitment_tx.0, remote_commitment_tx.1); self.channel_state |= ChannelState::AwaitingRemoteRevoke as u32; - Ok(msgs::CommitmentSigned { + Ok((msgs::CommitmentSigned { channel_id: self.channel_id, signature: our_sig, htlc_signatures: htlc_sigs, - }) + }, self.channel_monitor.clone())) } /// 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, onion_routing_packet: msgs::OnionPacket) -> Result, HandleError> { + pub fn send_htlc_and_commit(&mut self, amount_msat: u64, payment_hash: [u8; 32], cltv_expiry: u32, onion_routing_packet: msgs::OnionPacket) -> Result, HandleError> { match self.send_htlc(amount_msat, payment_hash, cltv_expiry, onion_routing_packet)? { - Some(update_add_htlc) => - Ok(Some((update_add_htlc, self.send_commitment_no_status_check()?))), + Some(update_add_htlc) => { + let (commitment_signed, monitor_update) = self.send_commitment_no_status_check()?; + Ok(Some((update_add_htlc, commitment_signed, monitor_update))) + }, None => Ok(None) } } @@ -2283,6 +2298,16 @@ impl Channel { scriptpubkey: our_closing_script, }, dropped_outbound_htlcs)) } + + /// Gets the latest commitment transaction and any dependant transactions for relay (forcing + /// shutdown of this channel - no more calls into this Channel may be made afterwards. + pub fn force_shutdown(&mut self) -> Vec { + assert!(self.channel_state != ChannelState::ShutdownComplete as u32); + self.channel_state = ChannelState::ShutdownComplete as u32; + let mut res = Vec::new(); + mem::swap(&mut res, &mut self.last_local_commitment_txn); + res + } } #[cfg(test)] diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 4fa34b4f..f612955b 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -608,41 +608,51 @@ impl ChannelManager { let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route)?; let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, associated_data)?; - let mut channel_state = self.channel_state.lock().unwrap(); - let id = match channel_state.short_to_id.get(&route.hops.first().unwrap().short_channel_id) { - None => return Err(HandleError{err: "No channel available with first hop!", msg: None}), - Some(id) => id.clone() - }; - let res = { - let chan = channel_state.by_id.get_mut(&id).unwrap(); - if chan.get_their_node_id() != route.hops.first().unwrap().pubkey { - return Err(HandleError{err: "Node ID mismatch on first hop!", msg: None}); + let (update_add, commitment_signed, chan_monitor) = { + let mut channel_state = self.channel_state.lock().unwrap(); + let id = match channel_state.short_to_id.get(&route.hops.first().unwrap().short_channel_id) { + None => return Err(HandleError{err: "No channel available with first hop!", msg: None}), + Some(id) => id.clone() + }; + let res = { + let chan = channel_state.by_id.get_mut(&id).unwrap(); + if chan.get_their_node_id() != route.hops.first().unwrap().pubkey { + return Err(HandleError{err: "Node ID mismatch on first hop!", msg: None}); + } + chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, onion_packet)? + }; + + if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { + route, + session_priv, + }).is_some() { + // TODO: We need to track these better, we're not generating these, so a + // third-party might make this happen: + panic!("payment_hash was repeated! Don't let this happen"); + } + + match res { + Some(msgs) => msgs, + None => return Ok(None), } - chan.send_htlc_and_commit(htlc_msat, payment_hash.clone(), htlc_cltv, onion_packet)? }; - if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { - route, - session_priv, - }).is_some() { - // TODO: We need to track these better, we're not generating these, so a - // third-party might make this happen: - panic!("payment_hash was repeated! Don't let this happen"); + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!(); // maybe remove from claimable_htlcs? } - - Ok(res) + Ok(Some((update_add, commitment_signed))) } /// Call this upon creation of a funding transaction for the given channel. /// Panics if a funding transaction has already been provided for this channel. pub fn funding_transaction_generated(&self, temporary_channel_id: &Uint256, funding_txo: (Sha256dHash, u16)) { - let (chan, msg) = { + let (chan, msg, chan_monitor) = { let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.remove(&temporary_channel_id) { Some(mut chan) => { match chan.get_outbound_funding_created(funding_txo.0, funding_txo.1) { Ok(funding_msg) => { - (chan, funding_msg) + (chan, funding_msg.0, funding_msg.1) }, Err(_e) => { //TODO: Push e to pendingevents @@ -653,15 +663,9 @@ impl ChannelManager { None => return } }; // Release channel lock for install_watch_outpoint call, - let chan_monitor = chan.channel_monitor(); - match self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { - Ok(()) => {}, - Err(_e) => { - //TODO: Push e to pendingevents? - return; - } - }; - + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!(); // maybe remove from claimable_htlcs? + } { let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::SendFundingCreated { @@ -741,25 +745,25 @@ impl ChannelManager { } if !add_htlc_msgs.is_empty() { - let commitment_msg = match forward_chan.send_commitment() { - Ok(msg) => msg, + let (commitment_msg, monitor) = match forward_chan.send_commitment() { + Ok(res) => res, Err(_) => { //TODO: Handle...this is bad! continue; }, }; - new_events.push(events::Event::SendHTLCs { + new_events.push((Some(monitor), events::Event::SendHTLCs { node_id: forward_chan.get_their_node_id(), msgs: add_htlc_msgs, commitment_msg: commitment_msg, - }); + })); } } else { for forward_info in pending_forwards { - new_events.push(events::Event::PaymentReceived { + new_events.push((None, events::Event::PaymentReceived { payment_hash: forward_info.payment_hash, amt: forward_info.amt_to_forward, - }); + })); } } } @@ -774,10 +778,19 @@ impl ChannelManager { if new_events.is_empty() { return } + new_events.retain(|event| { + if let &Some(ref monitor) = &event.0 { + if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor.clone()) { + unimplemented!();// but def dont push the event... + } + } + true + }); + let mut events = self.pending_events.lock().unwrap(); events.reserve(new_events.len()); for event in new_events.drain(..) { - events.push(event); + events.push(event.1); } } @@ -844,13 +857,18 @@ impl ChannelManager { }; match fail_msgs { - Some(msgs) => { + Some((msg, commitment_msg, chan_monitor)) => { mem::drop(channel_state); + + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!();// but def dont push the event... + } + let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::SendFailHTLC { node_id, - msg: msgs.0, - commitment_msg: msgs.1, + msg: msg, + commitment_msg: commitment_msg, }); }, None => {}, @@ -910,7 +928,7 @@ impl ChannelManager { false }, PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, .. } => { - let (node_id, fulfill_msgs, monitor) = { + let (node_id, fulfill_msgs) = { let chan_id = match channel_state.short_to_id.get(&source_short_channel_id) { Some(chan_id) => chan_id.clone(), None => return false @@ -918,7 +936,7 @@ impl ChannelManager { let chan = channel_state.by_id.get_mut(&chan_id).unwrap(); match chan.get_update_fulfill_htlc_and_commit(payment_preimage) { - Ok(msg) => (chan.get_their_node_id(), msg, if from_user { Some(chan.channel_monitor()) } else { None }), + Ok(msg) => (chan.get_their_node_id(), msg), Err(_e) => { //TODO: Do something with e? return false; @@ -928,25 +946,21 @@ impl ChannelManager { mem::drop(channel_state); match fulfill_msgs { - Some(msgs) => { + Some((msg, commitment_msg, chan_monitor)) => { + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!();// but def dont push the event... + } + let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::SendFulfillHTLC { node_id: node_id, - msg: msgs.0, - commitment_msg: msgs.1, + msg, + commitment_msg, }); }, None => {}, } - - //TODO: It may not be possible to handle add_update_monitor fails gracefully, maybe - //it should return no Err? Sadly, panic!()s instead doesn't help much :( - if from_user { - match self.monitor.add_update_monitor(monitor.as_ref().unwrap().get_funding_txo().unwrap(), monitor.unwrap()) { - Ok(()) => true, - Err(_) => true, - } - } else { true } + true }, } } @@ -955,6 +969,13 @@ impl ChannelManager { pub fn get_our_node_id(&self) -> PublicKey { PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).unwrap() } + + /// Used to restore channels to normal operation after a + /// ChannelMonitorUpdateErr::TemporaryFailure was returned from a channel monitor update + /// operation. + pub fn test_restore_channel_monitor(&self) { + unimplemented!(); + } } impl events::EventsProvider for ChannelManager { @@ -972,26 +993,47 @@ impl ChainListener for ChannelManager { { let mut channel_state = self.channel_state.lock().unwrap(); let mut short_to_ids_to_insert = Vec::new(); - for channel in channel_state.by_id.values_mut() { - match channel.block_connected(header, height, txn_matched, indexes_of_txn_matched) { - Some(funding_locked) => { - let announcement_sigs = match self.get_announcement_sigs(channel) { - Ok(res) => res, - Err(_e) => { - //TODO: push e on events and blow up the channel (it has bad keys) - continue; + let mut short_to_ids_to_remove = Vec::new(); + channel_state.by_id.retain(|_, channel| { + if let Some(funding_locked) = channel.block_connected(header, height, txn_matched, indexes_of_txn_matched) { + let announcement_sigs = match self.get_announcement_sigs(channel) { + Ok(res) => res, + Err(_e) => { + //TODO: push e on events and blow up the channel (it has bad keys) + return true; + } + }; + new_funding_locked_messages.push(events::Event::SendFundingLocked { + node_id: channel.get_their_node_id(), + msg: funding_locked, + announcement_sigs: announcement_sigs + }); + short_to_ids_to_insert.push((channel.get_short_channel_id().unwrap(), channel.channel_id())); + } + if let Some(funding_txo) = channel.get_funding_txo() { + for tx in txn_matched { + for inp in tx.input.iter() { + if inp.prev_hash == funding_txo.0 && inp.prev_index == funding_txo.1 as u32 { + if let Some(short_id) = channel.get_short_channel_id() { + short_to_ids_to_remove.push(short_id); + } + channel.force_shutdown(); + return false; } - }; - new_funding_locked_messages.push(events::Event::SendFundingLocked { - node_id: channel.get_their_node_id(), - msg: funding_locked, - announcement_sigs: announcement_sigs - }); - short_to_ids_to_insert.push((channel.get_short_channel_id().unwrap(), channel.channel_id())); - }, - None => {} + } + } } - //TODO: Check if channel was closed (or disabled) here + if channel.channel_monitor().would_broadcast_at_height(height) { + if let Some(short_id) = channel.get_short_channel_id() { + short_to_ids_to_remove.push(short_id); + } + channel.force_shutdown(); + return false; + } + true + }); + for to_remove in short_to_ids_to_remove { + channel_state.short_to_id.remove(&to_remove); } for to_insert in short_to_ids_to_insert { channel_state.short_to_id.insert(to_insert.0, to_insert.1); @@ -1078,7 +1120,7 @@ impl ChannelMessageHandler for ChannelManager { //TODO: broke this - a node shouldn't be able to get their channel removed by sending a //funding_created a second time, or long after the first, or whatever (note this also //leaves the short_to_id map in a busted state. - let chan = { + let (chan, funding_msg, monitor_update) = { let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.remove(&msg.temporary_channel_id) { Some(mut chan) => { @@ -1086,8 +1128,8 @@ impl ChannelMessageHandler for ChannelManager { return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) } match chan.funding_created(msg) { - Ok(funding_msg) => { - (chan, funding_msg) + Ok((funding_msg, monitor_update)) => { + (chan, funding_msg, monitor_update) }, Err(e) => { return Err(e); @@ -1100,27 +1142,31 @@ impl ChannelMessageHandler for ChannelManager { // note that this means if the remote end is misbehaving and sends a message for the same // channel back-to-back with funding_created, we'll end up thinking they sent a message // for a bogus channel. - let chan_monitor = chan.0.channel_monitor(); - self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor)?; + if let Err(_e) = self.monitor.add_update_monitor(monitor_update.get_funding_txo().unwrap(), monitor_update) { + unimplemented!(); + } let mut channel_state = self.channel_state.lock().unwrap(); - channel_state.by_id.insert(chan.1.channel_id, chan.0); - Ok(chan.1) + channel_state.by_id.insert(funding_msg.channel_id, chan); + Ok(funding_msg) } fn handle_funding_signed(&self, their_node_id: &PublicKey, msg: &msgs::FundingSigned) -> Result<(), HandleError> { - let (funding_txo, user_id) = { + let (funding_txo, user_id, monitor) = { let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.get_mut(&msg.channel_id) { Some(chan) => { if chan.get_their_node_id() != *their_node_id { return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) } - chan.funding_signed(&msg)?; - (chan.get_funding_txo().unwrap(), chan.get_user_id()) + let chan_monitor = chan.funding_signed(&msg)?; + (chan.get_funding_txo().unwrap(), chan.get_user_id(), chan_monitor) }, None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) } }; + if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) { + unimplemented!(); + } let mut pending_events = self.pending_events.lock().unwrap(); pending_events.push(events::Event::FundingBroadcastSafe { funding_txo: funding_txo, @@ -1446,13 +1492,14 @@ impl ChannelMessageHandler for ChannelManager { if chan.get_their_node_id() != *their_node_id { return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) } - chan.update_fulfill_htlc(&msg)?; - chan.channel_monitor() + chan.update_fulfill_htlc(&msg)? }, None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) } }; - self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?; + if let Err(_e) = self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor) { + unimplemented!(); + } Ok(()) } @@ -1545,38 +1592,41 @@ impl ChannelMessageHandler for ChannelManager { } fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option), HandleError> { - let (res, monitor) = { + let (revoke_and_ack, commitment_signed, chan_monitor) = { let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.get_mut(&msg.channel_id) { Some(chan) => { if chan.get_their_node_id() != *their_node_id { return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) } - (chan.commitment_signed(&msg)?, chan.channel_monitor()) + chan.commitment_signed(&msg)? }, None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) } }; - //TODO: Only if we store HTLC sigs - self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?; + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!(); + } - Ok(res) + Ok((revoke_and_ack, commitment_signed)) } fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &msgs::RevokeAndACK) -> Result, HandleError> { - let ((res, mut pending_forwards, mut pending_failures), monitor) = { + let (res, mut pending_forwards, mut pending_failures, chan_monitor) = { let mut channel_state = self.channel_state.lock().unwrap(); match channel_state.by_id.get_mut(&msg.channel_id) { Some(chan) => { if chan.get_their_node_id() != *their_node_id { return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None}) } - (chan.revoke_and_ack(&msg)?, chan.channel_monitor()) + chan.revoke_and_ack(&msg)? }, None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None}) } }; - self.monitor.add_update_monitor(monitor.get_funding_txo().unwrap(), monitor)?; + if let Err(_e) = self.monitor.add_update_monitor(chan_monitor.get_funding_txo().unwrap(), chan_monitor) { + unimplemented!(); + } for failure in pending_failures.drain(..) { self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failure.0, failure.1); } @@ -1673,8 +1723,10 @@ impl ChannelMessageHandler for ChannelManager { if let Some(short_id) = chan.get_short_channel_id() { short_to_id.remove(&short_id); } - //TODO: get the latest commitment tx, any HTLC txn built on top of it, etc out - //of the channel and throw those into the announcement blackhole. + let txn_to_broadcast = chan.force_shutdown(); + for tx in txn_to_broadcast { + self.tx_broadcaster.broadcast_transaction(&tx); + } false } else { true @@ -1723,6 +1775,7 @@ mod tests { use std::default::Default; use std::sync::{Arc, Mutex}; use std::time::Instant; + use std::mem; fn build_test_onion_keys() -> Vec { // Keys from BOLT 4, used in both test vector tests @@ -1940,6 +1993,12 @@ mod tests { }; node_a.node.handle_funding_signed(&node_b.node.get_our_node_id(), &funding_signed).unwrap(); + { + let mut added_monitors = node_a.chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + assert_eq!(added_monitors[0].0, funding_output); + added_monitors.clear(); + } let events_3 = node_a.node.get_and_clear_pending_events(); assert_eq!(events_3.len(), 1); @@ -2084,6 +2143,11 @@ mod tests { let mut payment_event = { let msgs = origin_node.node.send_payment(route, our_payment_hash).unwrap().unwrap(); + { + let mut added_monitors = origin_node.chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } SendEvent { node_id: expected_route[0].node.get_our_node_id(), msgs: vec!(msgs.0), @@ -2143,6 +2207,11 @@ mod tests { _ => panic!("Unexpected event"), } } else { + { + let mut added_monitors = node.chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } for event in events_2.drain(..) { payment_event = SendEvent::from_event(event); } @@ -2165,13 +2234,23 @@ mod tests { let mut next_msgs: Option<(msgs::UpdateFulfillHTLC, msgs::CommitmentSigned)> = None; macro_rules! update_fulfill_dance { - ($node: expr, $prev_node: expr) => { + ($node: expr, $prev_node: expr, $last_node: expr) => { { $node.node.handle_update_fulfill_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0).unwrap(); + { + let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap(); + if $last_node { + assert_eq!(added_monitors.len(), 1); + } else { + assert_eq!(added_monitors.len(), 2); + assert!(added_monitors[0].0 != added_monitors[1].0); + } + added_monitors.clear(); + } let revoke_and_commit = $node.node.handle_commitment_signed(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().1).unwrap(); { let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap(); - assert_eq!(added_monitors.len(), 2); + assert_eq!(added_monitors.len(), 1); added_monitors.clear(); } assert!($prev_node.node.handle_revoke_and_ack(&$node.node.get_our_node_id(), &revoke_and_commit.0).unwrap().is_none()); @@ -2197,7 +2276,7 @@ mod tests { for node in expected_route.iter().rev() { assert_eq!(expected_next_node, node.node.get_our_node_id()); if next_msgs.is_some() { - update_fulfill_dance!(node, prev_node); + update_fulfill_dance!(node, prev_node, false); } let events = node.node.get_and_clear_pending_events(); @@ -2214,7 +2293,7 @@ mod tests { } assert_eq!(expected_next_node, origin_node.node.get_our_node_id()); - update_fulfill_dance!(origin_node, expected_route.first().unwrap()); + update_fulfill_dance!(origin_node, expected_route.first().unwrap(), true); let events = origin_node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); @@ -2226,8 +2305,10 @@ mod tests { } } + const TEST_FINAL_CLTV: u32 = 32; + fn route_payment(origin_node: &Node, expected_route: &[&Node], recv_value: u64) -> ([u8; 32], [u8; 32]) { - let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, 142).unwrap(); + let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &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()) { assert_eq!(hop.pubkey, node.node.get_our_node_id()); @@ -2237,7 +2318,7 @@ mod tests { } fn route_over_limit(origin_node: &Node, expected_route: &[&Node], recv_value: u64) { - let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), recv_value, 142).unwrap(); + let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &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()) { assert_eq!(hop.pubkey, node.node.get_our_node_id()); @@ -2264,30 +2345,47 @@ mod tests { fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: [u8; 32]) { assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash)); + { + let mut added_monitors = expected_route.last().unwrap().chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } let mut next_msgs: Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)> = None; macro_rules! update_fail_dance { - ($node: expr, $prev_node: expr) => { + ($node: expr, $prev_node: expr, $last_node: expr) => { { $node.node.handle_update_fail_htlc(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().0).unwrap(); let revoke_and_commit = $node.node.handle_commitment_signed(&$prev_node.node.get_our_node_id(), &next_msgs.as_ref().unwrap().1).unwrap(); + { let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap(); assert_eq!(added_monitors.len(), 1); added_monitors.clear(); } assert!($prev_node.node.handle_revoke_and_ack(&$node.node.get_our_node_id(), &revoke_and_commit.0).unwrap().is_none()); + { + let mut added_monitors = $prev_node.chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } let revoke_and_ack = $prev_node.node.handle_commitment_signed(&$node.node.get_our_node_id(), &revoke_and_commit.1.unwrap()).unwrap(); - assert!(revoke_and_ack.1.is_none()); { let mut added_monitors = $prev_node.chan_monitor.added_monitors.lock().unwrap(); - assert_eq!(added_monitors.len(), 2); + assert_eq!(added_monitors.len(), 1); added_monitors.clear(); } + assert!(revoke_and_ack.1.is_none()); + assert!($node.node.get_and_clear_pending_events().is_empty()); assert!($node.node.handle_revoke_and_ack(&$prev_node.node.get_our_node_id(), &revoke_and_ack.0).unwrap().is_none()); { let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap(); - assert_eq!(added_monitors.len(), 1); + if $last_node { + assert_eq!(added_monitors.len(), 1); + } else { + assert_eq!(added_monitors.len(), 2); + assert!(added_monitors[0].0 != added_monitors[1].0); + } added_monitors.clear(); } } @@ -2299,7 +2397,7 @@ mod tests { for node in expected_route.iter().rev() { assert_eq!(expected_next_node, node.node.get_our_node_id()); if next_msgs.is_some() { - update_fail_dance!(node, prev_node); + update_fail_dance!(node, prev_node, false); } let events = node.node.get_and_clear_pending_events(); @@ -2316,7 +2414,7 @@ mod tests { } assert_eq!(expected_next_node, origin_node.node.get_our_node_id()); - update_fail_dance!(origin_node, expected_route.first().unwrap()); + update_fail_dance!(origin_node, expected_route.first().unwrap(), true); let events = origin_node.node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); @@ -2406,7 +2504,7 @@ mod tests { pubkey: nodes[1].node.get_our_node_id(), short_channel_id: chan_4.0.contents.short_channel_id, fee_msat: 1000000, - cltv_expiry_delta: 142, + cltv_expiry_delta: TEST_FINAL_CLTV, }); hops[1].fee_msat = chan_4.1.contents.fee_base_msat as u64 + chan_4.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000; hops[0].fee_msat = chan_3.0.contents.fee_base_msat as u64 + chan_3.0.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000; @@ -2429,7 +2527,7 @@ mod tests { pubkey: nodes[1].node.get_our_node_id(), short_channel_id: chan_2.0.contents.short_channel_id, fee_msat: 1000000, - cltv_expiry_delta: 142, + cltv_expiry_delta: TEST_FINAL_CLTV, }); hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000; hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000; @@ -2468,4 +2566,233 @@ mod tests { assert_eq!(node.chan_monitor.added_monitors.lock().unwrap().len(), 0); } } + + #[derive(PartialEq)] + enum HTLCType { NONE, TIMEOUT, SUCCESS } + fn test_txn_broadcast(node: &Node, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, Uint256, Transaction), commitment_tx: Option, has_htlc_tx: HTLCType) -> Vec { + let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert!(node_txn.len() >= if commitment_tx.is_some() { 0 } else { 1 } + if has_htlc_tx == HTLCType::NONE { 0 } else { 1 }); + + let mut res = Vec::with_capacity(2); + + if let Some(explicit_tx) = commitment_tx { + res.push(explicit_tx.clone()); + } else { + for tx in node_txn.iter() { + if tx.input.len() == 1 && tx.input[0].prev_hash == chan.3.txid() { + let mut funding_tx_map = HashMap::new(); + funding_tx_map.insert(chan.3.txid(), chan.3.clone()); + tx.verify(&funding_tx_map).unwrap(); + res.push(tx.clone()); + } + } + } + assert_eq!(res.len(), 1); + + if has_htlc_tx != HTLCType::NONE { + for tx in node_txn.iter() { + if tx.input.len() == 1 && tx.input[0].prev_hash == res[0].txid() { + let mut funding_tx_map = HashMap::new(); + funding_tx_map.insert(res[0].txid(), res[0].clone()); + tx.verify(&funding_tx_map).unwrap(); + if has_htlc_tx == HTLCType::TIMEOUT { + assert!(tx.lock_time != 0); + } else { + assert!(tx.lock_time == 0); + } + res.push(tx.clone()); + break; + } + } + assert_eq!(res.len(), 2); + } + node_txn.clear(); + res + } + + fn check_preimage_claim(node: &Node, prev_txn: &Vec) -> Vec { + let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap(); + + assert!(node_txn.len() >= 1); + assert_eq!(node_txn[0].input.len(), 1); + let mut found_prev = false; + + for tx in prev_txn { + if node_txn[0].input[0].prev_hash == tx.txid() { + let mut funding_tx_map = HashMap::new(); + funding_tx_map.insert(tx.txid(), tx.clone()); + node_txn[0].verify(&funding_tx_map).unwrap(); + + assert!(node_txn[0].input[0].witness[2].len() > 106); // must spend an htlc output + assert_eq!(tx.input.len(), 1); // must spend a commitment tx + + found_prev = true; + break; + } + } + assert!(found_prev); + + let mut res = Vec::new(); + mem::swap(&mut *node_txn, &mut res); + res + } + + #[test] + fn channel_monitor_network_test() { + // Simple test which builds a network of ChannelManagers, connects them to each other, and + // tests that ChannelMonitor is able to recover from various states. + let nodes = create_network(5); + + // 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); + let chan_3 = create_announced_chan_between_nodes(&nodes, 2, 3); + let chan_4 = create_announced_chan_between_nodes(&nodes, 3, 4); + + // Rebalance the network a bit by relaying one payment through all the channels... + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000); + send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3], &nodes[4])[..], 8000000); + + // Simple case with no pending HTLCs: + nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), true); + { + let node_txn = test_txn_broadcast(&nodes[1], &chan_1, None, HTLCType::NONE); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]); + assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0); + } + assert_eq!(nodes[0].node.list_channels().len(), 0); + assert_eq!(nodes[1].node.list_channels().len(), 1); + + // One pending HTLC is discarded by the force-close: + let payment_preimage_1 = route_payment(&nodes[1], &vec!(&nodes[2], &nodes[3])[..], 3000000).0; + + // Simple case of one pending HTLC to HTLC-Timeout + nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), true); + { + let node_txn = test_txn_broadcast(&nodes[1], &chan_2, None, HTLCType::TIMEOUT); + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[2].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]); + assert_eq!(nodes[2].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 0); + } + assert_eq!(nodes[1].node.list_channels().len(), 0); + assert_eq!(nodes[2].node.list_channels().len(), 1); + + macro_rules! claim_funds { + ($node: expr, $prev_node: expr, $preimage: expr) => { + { + assert!($node.node.claim_funds($preimage)); + { + let mut added_monitors = $node.chan_monitor.added_monitors.lock().unwrap(); + assert_eq!(added_monitors.len(), 1); + added_monitors.clear(); + } + + let events = $node.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::SendFulfillHTLC { ref node_id, .. } => { + assert_eq!(*node_id, $prev_node.node.get_our_node_id()); + }, + _ => panic!("Unexpected event"), + }; + } + } + } + + // nodes[3] gets the preimage, but nodes[2] already disconnected, resulting in a nodes[2] + // HTLC-Timeout and a nodes[3] claim against it (+ its own announces) + nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id(), true); + { + let node_txn = test_txn_broadcast(&nodes[2], &chan_3, None, HTLCType::TIMEOUT); + + // Claim the payment on nodes[3], giving it knowledge of the preimage + claim_funds!(nodes[3], nodes[2], payment_preimage_1); + + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[3].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[0]; 1], &[4; 1]); + + check_preimage_claim(&nodes[3], &node_txn); + } + assert_eq!(nodes[2].node.list_channels().len(), 0); + assert_eq!(nodes[3].node.list_channels().len(), 1); + + // One pending HTLC to time out: + let payment_preimage_2 = route_payment(&nodes[3], &vec!(&nodes[4])[..], 3000000).0; + + { + let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[3].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]); + for i in 2..TEST_FINAL_CLTV - 5 { + header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[3].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]); + } + + let node_txn = test_txn_broadcast(&nodes[3], &chan_4, None, HTLCType::TIMEOUT); + + // Claim the payment on nodes[3], giving it knowledge of the preimage + claim_funds!(nodes[4], nodes[3], payment_preimage_2); + + header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[4].chain_monitor.block_connected_checked(&header, 1, &Vec::new()[..], &[0; 0]); + for i in 2..TEST_FINAL_CLTV - 5 { + header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[4].chain_monitor.block_connected_checked(&header, i, &Vec::new()[..], &[0; 0]); + } + + test_txn_broadcast(&nodes[4], &chan_4, None, HTLCType::SUCCESS); + + header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[4].chain_monitor.block_connected_checked(&header, TEST_FINAL_CLTV - 5, &[&node_txn[0]; 1], &[4; 1]); + + check_preimage_claim(&nodes[4], &node_txn); + } + assert_eq!(nodes[3].node.list_channels().len(), 0); + assert_eq!(nodes[4].node.list_channels().len(), 0); + + // TODO: Need to reenable this when we fix local route tracking + // Create some new channels: + /*let chan_5 = create_announced_chan_between_nodes(&nodes, 0, 1); + + // A pending HTLC which will be revoked: + let payment_preimage_3 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0; + // Get the will-be-revoked local txn from nodes[0] + let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.iter().next().unwrap().1.last_local_commitment_txn.clone(); + // Revoke the old state + claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_3); + + { + let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[1].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 1]); + { + let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(node_txn.len(), 1); + assert_eq!(node_txn[0].input.len(), 1); + + let mut funding_tx_map = HashMap::new(); + funding_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone()); + node_txn[0].verify(&funding_tx_map).unwrap(); + node_txn.clear(); + } + + nodes[0].chain_monitor.block_connected_checked(&header, 1, &vec![&revoked_local_txn[0]; 1], &[4; 0]); + let node_txn = test_txn_broadcast(&nodes[0], &chan_5, Some(revoked_local_txn[0].clone()), HTLCType::TIMEOUT); + header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[1].chain_monitor.block_connected_checked(&header, 1, &[&node_txn[1]; 1], &[4; 1]); + + //TODO: At this point nodes[1] should claim the revoked HTLC-Timeout output, but that's + //not yet implemented in ChannelMonitor + } + get_announce_close_broadcast_events(&nodes, 0, 1); + assert_eq!(nodes[0].node.list_channels().len(), 0); + assert_eq!(nodes[1].node.list_channels().len(), 0);*/ + + // Check that we processed all pending events + for node in nodes { + assert_eq!(node.node.get_and_clear_pending_events().len(), 0); + assert_eq!(node.chan_monitor.added_monitors.lock().unwrap().len(), 0); + } + } } diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index 3021163f..c36df8e7 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -19,13 +19,31 @@ use std::collections::HashMap; use std::sync::{Arc,Mutex}; use std::{hash,cmp}; +pub enum ChannelMonitorUpdateErr { + /// Used to indicate a temporary failure (eg connection to a watchtower failed, but is expected + /// to succeed at some point in the future). + /// Such a failure will "freeze" a channel, preventing us from revoking old states or + /// submitting new commitment transactions to the remote party. + /// ChannelManager::test_restore_channel_monitor can be used to retry the update(s) and restore + /// the channel to an operational state. + TemporaryFailure, + /// Used to indicate no further channel monitor updates will be allowed (eg we've moved on to a + /// different watchtower and cannot update with all watchtowers that were previously informed + /// of this channel). This will force-close the channel in question. + PermanentFailure, +} + /// 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 /// server(s). +/// Note that any updates to a channel's monitor *must* be applied to each instance of the +/// channel's monitor everywhere (including remote watchtowers) *before* this function returns. If +/// an update occurs and a remote watchtower is left with old state, it may broadcast transactions +/// which we have revoked, allowing our counterparty to claim all funds in the channel! pub trait ManyChannelMonitor: Send + Sync { /// Adds or updates a monitor for the given funding_txid+funding_output_index. - fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), HandleError>; + fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; } /// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a @@ -81,68 +99,129 @@ impl SimpleManyChannelMonitor } impl ManyChannelMonitor for SimpleManyChannelMonitor<(Sha256dHash, u16)> { - fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), HandleError> { - self.add_update_monitor_by_key(funding_txo, monitor) + fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { + match self.add_update_monitor_by_key(funding_txo, monitor) { + Ok(_) => Ok(()), + Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), + } } } -/// If an HTLC expires within this many blocks, don't try to claim it directly, instead broadcast -/// the HTLC-Success/HTLC-Timeout transaction and claim the revocation from that. -const CLTV_CLAIM_BUFFER: u32 = 12; +/// If an HTLC expires within this many blocks, don't try to claim it in a shared transaction, +/// instead claiming it in its own individual transaction. +const CLTV_SHARED_CLAIM_BUFFER: u32 = 12; +/// If an HTLC expires within this many blocks, force-close the channel to broadcast the +/// HTLC-Success transaction. +const CLTV_CLAIM_BUFFER: u32 = 6; #[derive(Clone)] -enum RevocationStorage { +enum KeyStorage { PrivMode { revocation_base_key: SecretKey, + htlc_base_key: SecretKey, }, SigsMode { revocation_base_key: PublicKey, + htlc_base_key: PublicKey, sigs: HashMap, } } #[derive(Clone)] -struct PerCommitmentTransactionData { - revoked_output_index: u32, - htlcs: Vec<(HTLCOutputInCommitment, Signature)>, +struct LocalSignedTx { + txid: Sha256dHash, + tx: Transaction, + revocation_key: PublicKey, + a_htlc_key: PublicKey, + b_htlc_key: PublicKey, + delayed_payment_key: PublicKey, + feerate_per_kw: u64, + htlc_outputs: Vec<(HTLCOutputInCommitment, Signature, Signature)>, } -#[derive(Clone)] pub struct ChannelMonitor { funding_txo: Option<(Sha256dHash, u16)>, commitment_transaction_number_obscure_factor: u64, - revocation_base_key: RevocationStorage, + key_storage: KeyStorage, delayed_payment_base_key: PublicKey, - htlc_base_key: PublicKey, their_htlc_base_key: Option, - to_self_delay: u16, + // first is the idx of the first of the two revocation points + their_cur_revocation_points: Option<(u64, PublicKey, Option)>, + + our_to_self_delay: u16, + their_to_self_delay: Option, old_secrets: [([u8; 32], u64); 49], - claimable_outpoints: HashMap, - payment_preimages: Vec<[u8; 32]>, + remote_claimable_outpoints: HashMap>, + remote_htlc_outputs_on_chain: Mutex>, + + // 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 + // various monitors for one channel being out of sync, and us broadcasting a local + // transaction for which we have deleted claim information on some watchtowers. + prev_local_signed_commitment_tx: Option, + current_local_signed_commitment_tx: Option, + + payment_preimages: HashMap<[u8; 32], [u8; 32]>, destination_script: Script, secp_ctx: Secp256k1, //TODO: dedup this a bit... } +impl Clone for ChannelMonitor { + fn clone(&self) -> Self { + ChannelMonitor { + funding_txo: self.funding_txo.clone(), + commitment_transaction_number_obscure_factor: self.commitment_transaction_number_obscure_factor.clone(), + + key_storage: self.key_storage.clone(), + delayed_payment_base_key: self.delayed_payment_base_key.clone(), + their_htlc_base_key: self.their_htlc_base_key.clone(), + their_cur_revocation_points: self.their_cur_revocation_points.clone(), + + our_to_self_delay: self.our_to_self_delay, + their_to_self_delay: self.their_to_self_delay, + + old_secrets: self.old_secrets.clone(), + remote_claimable_outpoints: self.remote_claimable_outpoints.clone(), + remote_htlc_outputs_on_chain: Mutex::new((*self.remote_htlc_outputs_on_chain.lock().unwrap()).clone()), + + prev_local_signed_commitment_tx: self.prev_local_signed_commitment_tx.clone(), + current_local_signed_commitment_tx: self.current_local_signed_commitment_tx.clone(), + + payment_preimages: self.payment_preimages.clone(), + + destination_script: self.destination_script.clone(), + secp_ctx: self.secp_ctx.clone(), + } + } +} impl ChannelMonitor { - pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &PublicKey, to_self_delay: u16, destination_script: Script) -> ChannelMonitor { + pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor { ChannelMonitor { funding_txo: None, commitment_transaction_number_obscure_factor: 0, - revocation_base_key: RevocationStorage::PrivMode { + key_storage: KeyStorage::PrivMode { revocation_base_key: revocation_base_key.clone(), + htlc_base_key: htlc_base_key.clone(), }, delayed_payment_base_key: delayed_payment_base_key.clone(), - htlc_base_key: htlc_base_key.clone(), their_htlc_base_key: None, - to_self_delay: to_self_delay, + their_cur_revocation_points: None, + + our_to_self_delay: our_to_self_delay, + their_to_self_delay: None, old_secrets: [([0; 32], 1 << 48); 49], - claimable_outpoints: HashMap::new(), - payment_preimages: Vec::new(), + remote_claimable_outpoints: HashMap::new(), + remote_htlc_outputs_on_chain: Mutex::new(HashMap::new()), + + prev_local_signed_commitment_tx: None, + current_local_signed_commitment_tx: None, + + payment_preimages: HashMap::new(), destination_script: destination_script, secp_ctx: Secp256k1::new(), @@ -174,10 +253,10 @@ impl ChannelMonitor { res } - /// Inserts a revocation secret into this channel monitor. Requires the revocation_base_key of - /// the node which we are monitoring the channel on behalf of in order to generate signatures - /// over revocation-claim transactions. - pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), HandleError> { + /// Inserts a revocation secret into this channel monitor. Also optionally tracks the next + /// revocation point which may be required to claim HTLC outputs which we know the preimage of + /// in case the remote end force-closes using their latest state. + pub fn provide_secret(&mut self, idx: u64, secret: [u8; 32], their_next_revocation_point: Option<(u64, PublicKey)>) -> Result<(), HandleError> { let pos = ChannelMonitor::place_secret(idx); for i in 0..pos { let (old_secret, old_idx) = self.old_secrets[i as usize]; @@ -186,25 +265,71 @@ impl ChannelMonitor { } } self.old_secrets[pos as usize] = (secret, idx); + + if let Some(new_revocation_point) = their_next_revocation_point { + match self.their_cur_revocation_points { + Some(old_points) => { + if old_points.0 == new_revocation_point.0 + 1 { + self.their_cur_revocation_points = Some((old_points.0, old_points.1, Some(new_revocation_point.1))); + } else if old_points.0 == new_revocation_point.0 + 2 { + if let Some(old_second_point) = old_points.2 { + self.their_cur_revocation_points = Some((old_points.0 - 1, old_second_point, Some(new_revocation_point.1))); + } else { + self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None)); + } + } else { + self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None)); + } + }, + None => { + self.their_cur_revocation_points = Some((new_revocation_point.0, new_revocation_point.1, None)); + } + } + } + // TODO: Prune payment_preimages no longer needed by the revocation (just have to check + // that non-revoked remote commitment tx(n) do not need it, and our latest local commitment + // tx does not need it. Ok(()) } - /// Informs this watcher of the set of HTLC outputs in a commitment transaction which our - /// counterparty may broadcast. This allows us to reconstruct the commitment transaction's - /// outputs fully, claiming revoked, unexpired HTLC outputs as well as revoked refund outputs. - /// TODO: Doc new params! - /// TODO: This seems to be wrong...we should be calling this from commitment_signed, but we - /// should be calling this about remote transactions, ie ones that they can revoke_and_ack... - pub fn provide_tx_info(&mut self, commitment_tx: &Transaction, revokeable_out_index: u32, htlc_outputs: Vec<(HTLCOutputInCommitment, Signature)>) { + /// Informs this monitor of the latest remote (ie non-broadcastable) commitment transaction. + /// 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. + pub fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec) { // 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. - self.claimable_outpoints.insert(commitment_tx.txid(), PerCommitmentTransactionData{ - revoked_output_index: revokeable_out_index, - htlcs: htlc_outputs + // (only maybe, sadly we cant do the same for local info, as we need to be aware of + // timeouts) + self.remote_claimable_outpoints.insert(unsigned_commitment_tx.txid(), htlc_outputs); + } + + /// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The + /// monitor watches for timeouts and may broadcast it if we approach such a timeout. Thus, it + /// is important that any clones of this channel monitor (including remote clones) by kept + /// up-to-date as our local commitment transaction is updated. + /// Panics if set_their_to_self_delay has never been called. + pub 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)>) { + 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 { + txid: signed_commitment_tx.txid(), + tx: signed_commitment_tx, + revocation_key: local_keys.revocation_key, + a_htlc_key: local_keys.a_htlc_key, + b_htlc_key: local_keys.b_htlc_key, + delayed_payment_key: local_keys.a_delayed_payment_key, + feerate_per_kw, + htlc_outputs, }); } - pub fn insert_combine(&mut self, other: ChannelMonitor) -> Result<(), HandleError> { + /// 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 fn provide_payment_preimage(&mut self, payment_hash: &[u8; 32], payment_preimage: &[u8; 32]) { + self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone()); + } + + pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), HandleError> { match self.funding_txo { Some(txo) => if other.funding_txo.is_some() && other.funding_txo.unwrap() != txo { return Err(HandleError{err: "Funding transaction outputs are not identical!", msg: None}); @@ -213,10 +338,25 @@ impl ChannelMonitor { self.funding_txo = other.funding_txo; } } - let other_max_secret = other.get_min_seen_secret(); - if self.get_min_seen_secret() > other_max_secret { - self.provide_secret(other_max_secret, other.get_secret(other_max_secret).unwrap()) - } else { Ok(()) } + let other_min_secret = other.get_min_seen_secret(); + let our_min_secret = self.get_min_seen_secret(); + if our_min_secret > other_min_secret { + self.provide_secret(other_min_secret, other.get_secret(other_min_secret).unwrap(), None)?; + } + if our_min_secret >= other_min_secret { + self.their_cur_revocation_points = other.their_cur_revocation_points; + for (txid, htlcs) in other.remote_claimable_outpoints.drain() { + self.remote_claimable_outpoints.insert(txid, htlcs); + } + if let Some(local_tx) = other.prev_local_signed_commitment_tx { + self.prev_local_signed_commitment_tx = Some(local_tx); + } + if let Some(local_tx) = other.current_local_signed_commitment_tx { + self.current_local_signed_commitment_tx = Some(local_tx); + } + self.payment_preimages = other.payment_preimages; + } + Ok(()) } /// Panics if commitment_transaction_number_obscure_factor doesn't fit in 48 bits @@ -237,6 +377,10 @@ impl ChannelMonitor { self.their_htlc_base_key = Some(their_htlc_base_key.clone()); } + pub fn set_their_to_self_delay(&mut self, their_to_self_delay: u16) { + self.their_to_self_delay = Some(their_to_self_delay); + } + pub fn unset_funding_info(&mut self) { self.funding_txo = None; } @@ -270,113 +414,147 @@ impl ChannelMonitor { min } - pub fn provide_payment_preimage(&mut self, payment_preimage: &[u8; 32]) { - //TODO: Some kind of timeout here or ability to mark all states containing this preimage - //revoked? - self.payment_preimages.push(payment_preimage.clone()); - } - - #[inline] - fn check_spend_transaction(&self, tx: &Transaction, height: u32) -> Vec { + /// Attempts to claim a remote commitment transaction's outputs using the revocation key and + /// 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, and claim them using the revocation key (if + /// applicable) as well. + fn check_spend_remote_transaction(&self, tx: &Transaction, height: u32) -> Vec { // 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(); macro_rules! ignore_error { ( $thing : expr ) => { match $thing { Ok(a) => a, - Err(_) => return Vec::new() + Err(_) => return txn_to_broadcast } }; } - let mut txn_to_broadcast = 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); let commitment_number = (((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor; if commitment_number >= self.get_min_seen_secret() { let secret = self.get_secret(commitment_number).unwrap(); let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret)); - let revocation_pubkey = match self.revocation_base_key { - RevocationStorage::PrivMode { ref revocation_base_key } => { - ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))) + let (revocation_pubkey, b_htlc_key) = match self.key_storage { + KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => { + let per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)); + (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))), + ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))) }, - RevocationStorage::SigsMode { ref revocation_base_key, .. } => { - ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &revocation_base_key)) + KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => { + let per_commitment_point = ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)); + (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &revocation_base_key)), + ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &htlc_base_key))) }, }; let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &self.delayed_payment_base_key)); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &self.htlc_base_key)); - let b_htlc_key = match self.their_htlc_base_key { - None => return Vec::new(), + let a_htlc_key = match self.their_htlc_base_key { + None => return txn_to_broadcast, Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key)), &their_htlc_base_key)), }; - let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.to_self_delay, &delayed_key); - - let commitment_txid = tx.txid(); + let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); + let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); let mut total_value = 0; let mut values = Vec::new(); - let inputs = match self.claimable_outpoints.get(&commitment_txid) { - Some(per_commitment_data) => { - let mut inp = Vec::with_capacity(per_commitment_data.htlcs.len() + 1); - - if per_commitment_data.revoked_output_index as usize >= tx.output.len() || tx.output[per_commitment_data.revoked_output_index as usize].script_pubkey != revokeable_redeemscript.to_v0_p2wsh() { - return Vec::new(); // Corrupted per_commitment_data, not much we can do - } + let mut inputs = Vec::new(); + let mut htlc_idxs = Vec::new(); - inp.push(TxIn { + for (idx, outp) in tx.output.iter().enumerate() { + if outp.script_pubkey == revokeable_p2wsh { + inputs.push(TxIn { prev_hash: commitment_txid, - prev_index: per_commitment_data.revoked_output_index, + prev_index: idx as u32, script_sig: Script::new(), - sequence: 0xffffffff, + sequence: 0xfffffffd, witness: Vec::new(), }); - values.push(tx.output[per_commitment_data.revoked_output_index as usize].value); - total_value += tx.output[per_commitment_data.revoked_output_index as usize].value; - - for &(ref htlc, ref _next_tx_sig) in per_commitment_data.htlcs.iter() { - 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 Vec::new(); // Corrupted per_commitment_data, fuck this user - } - if htlc.cltv_expiry > height + CLTV_CLAIM_BUFFER { - inp.push(TxIn { - prev_hash: commitment_txid, - prev_index: htlc.transaction_output_index, - script_sig: Script::new(), - sequence: 0xffffffff, - witness: Vec::new(), - }); - values.push(tx.output[htlc.transaction_output_index as usize].value); - total_value += htlc.amount_msat / 1000; + htlc_idxs.push(None); + values.push(outp.value); + total_value += outp.value; + break; // There can only be one of these + } + } + + macro_rules! sign_input { + ($sighash_parts: expr, $input: expr, $htlc_idx: expr, $amount: expr) => { + { + let (sig, redeemscript) = match self.key_storage { + KeyStorage::PrivMode { ref revocation_base_key, .. } => { + let redeemscript = if $htlc_idx.is_none() { revokeable_redeemscript.clone() } else { + let htlc = &per_commitment_option.unwrap()[$htlc_idx.unwrap()]; + 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 revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key)); + (ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key)), redeemscript) + }, + KeyStorage::SigsMode { .. } => { + unimplemented!(); + } + }; + $input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec()); + $input.witness[0].push(SigHashType::All as u8); + if $htlc_idx.is_none() { + $input.witness.push(vec!(1)); } else { - //TODO: Mark as "bad" - //then broadcast using next_tx_sig + $input.witness.push(revocation_pubkey.serialize().to_vec()); } + $input.witness.push(redeemscript.into_vec()); } - inp - }, None => { - let mut inp = Vec::new(); // This is unlikely to succeed - for (idx, outp) in tx.output.iter().enumerate() { - if outp.script_pubkey == revokeable_redeemscript.to_v0_p2wsh() { - inp.push(TxIn { - prev_hash: commitment_txid, - prev_index: idx as u32, - script_sig: Script::new(), - sequence: 0xffffffff, - witness: Vec::new(), - }); - values.push(outp.value); - total_value += outp.value; - break; // There can only be one of these - } + } + } + + 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() { + 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; // Corrupted per_commitment_data, fuck this user + } + let input = TxIn { + prev_hash: commitment_txid, + prev_index: htlc.transaction_output_index, + script_sig: Script::new(), + sequence: 0xfffffffd, + witness: Vec::new(), + }; + if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER { + inputs.push(input); + htlc_idxs.push(Some(idx)); + values.push(tx.output[htlc.transaction_output_index as usize].value); + total_value += htlc.amount_msat / 1000; + } else { + let mut single_htlc_tx = Transaction { + version: 2, + lock_time: 0, + input: vec![input], + output: vec!(TxOut { + script_pubkey: self.destination_script.clone(), + value: htlc.amount_msat / 1000, //TODO: - fee + }), + }; + let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx); + sign_input!(sighash_parts, single_htlc_tx.input[0], Some(idx), htlc.amount_msat / 1000); + txn_to_broadcast.push(single_htlc_tx); // TODO: This is not yet tested in ChannelManager! } - if inp.is_empty() { return Vec::new(); } // Nothing to be done...probably a false positive - inp } - }; + } + + if !inputs.is_empty() || !txn_to_broadcast.is_empty() { + // We're definitely a remote commitment transaction! + // TODO: Register commitment_txid with the ChainWatchInterface! + self.remote_htlc_outputs_on_chain.lock().unwrap().insert(commitment_txid, commitment_number); + } + if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx let outputs = vec!(TxOut { script_pubkey: self.destination_script.clone(), @@ -390,82 +568,227 @@ impl ChannelMonitor { }; let mut values_drain = values.drain(..); - - // First input is the generic revokeable_redeemscript let sighash_parts = bip143::SighashComponents::new(&spend_tx); - { - let sig = match self.revocation_base_key { - RevocationStorage::PrivMode { ref revocation_base_key } => { - let sighash = ignore_error!(Message::from_slice(&sighash_parts.sighash_all(&spend_tx.input[0], &revokeable_redeemscript, values_drain.next().unwrap())[..])); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key)); - ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key)) - }, - RevocationStorage::SigsMode { .. } => { - unimplemented!(); - } - }; - spend_tx.input[0].witness.push(sig.serialize_der(&self.secp_ctx).to_vec()); - spend_tx.input[0].witness[0].push(SigHashType::All as u8); - spend_tx.input[0].witness.push(vec!(1)); // First if branch is revocation_key + for (input, htlc_idx) in spend_tx.input.iter_mut().zip(htlc_idxs.iter()) { + let value = values_drain.next().unwrap(); + sign_input!(sighash_parts, input, htlc_idx, value); } - match self.claimable_outpoints.get(&commitment_txid) { - None => {}, - Some(per_commitment_data) => { - let mut htlc_idx = 0; - for (idx, input) in spend_tx.input.iter_mut().enumerate() { - if idx == 0 { continue; } // We already signed the first input - - let mut htlc; - while { - htlc = &per_commitment_data.htlcs[htlc_idx].0; - htlc_idx += 1; - htlc.cltv_expiry > height + CLTV_CLAIM_BUFFER - } {} - - let sig = match self.revocation_base_key { - RevocationStorage::PrivMode { ref revocation_base_key } => { - let htlc_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, &htlc_redeemscript, values_drain.next().unwrap())[..])); + txn_to_broadcast.push(spend_tx); + } else if let Some(per_commitment_data) = per_commitment_option { + if let Some(revocation_points) = self.their_cur_revocation_points { + let revocation_point_option = + if revocation_points.0 == commitment_number { Some(&revocation_points.1) } + else if let Some(point) = revocation_points.2.as_ref() { + if revocation_points.0 == commitment_number + 1 { Some(point) } else { None } + } else { None }; + if let Some(revocation_point) = revocation_point_option { + let (revocation_pubkey, b_htlc_key) = match self.key_storage { + KeyStorage::PrivMode { ref revocation_base_key, ref htlc_base_key } => { + (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &revocation_base_key)))), + ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &ignore_error!(PublicKey::from_secret_key(&self.secp_ctx, &htlc_base_key))))) + }, + KeyStorage::SigsMode { ref revocation_base_key, ref htlc_base_key, .. } => { + (ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &revocation_base_key)), + ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &htlc_base_key))) + }, + }; + let a_htlc_key = match self.their_htlc_base_key { + None => return txn_to_broadcast, + Some(their_htlc_base_key) => ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &their_htlc_base_key)), + }; + + let mut total_value = 0; + let mut values = Vec::new(); + let mut inputs = Vec::new(); + + macro_rules! sign_input { + ($sighash_parts: expr, $input: expr, $amount: expr, $preimage: expr) => { + { + let (sig, redeemscript) = match self.key_storage { + KeyStorage::PrivMode { ref htlc_base_key, .. } => { + let htlc = &per_commitment_option.unwrap()[$input.sequence as usize]; + 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)); + (ignore_error!(self.secp_ctx.sign(&sighash, &htlc_key)), redeemscript) + }, + KeyStorage::SigsMode { .. } => { + unimplemented!(); + } + }; + $input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec()); + $input.witness[0].push(SigHashType::All as u8); + $input.witness.push($preimage); + $input.witness.push(redeemscript.into_vec()); + } + } + } - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &revocation_base_key)); - ignore_error!(self.secp_ctx.sign(&sighash, &revocation_key)) - }, - RevocationStorage::SigsMode { .. } => { - unimplemented!(); + for (idx, htlc) in per_commitment_data.iter().enumerate() { + if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) { + let input = TxIn { + prev_hash: commitment_txid, + prev_index: htlc.transaction_output_index, + script_sig: Script::new(), + sequence: idx as u32, // reset to 0xfffffffd in sign_input + witness: Vec::new(), + }; + if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER { + inputs.push(input); + values.push((tx.output[htlc.transaction_output_index as usize].value, payment_preimage)); + total_value += htlc.amount_msat / 1000; + } else { + let mut single_htlc_tx = Transaction { + version: 2, + lock_time: 0, + input: vec![input], + output: vec!(TxOut { + script_pubkey: self.destination_script.clone(), + value: htlc.amount_msat / 1000, //TODO: - fee + }), + }; + 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()); + txn_to_broadcast.push(single_htlc_tx); } - }; + } + } - input.witness.push(revocation_pubkey.serialize().to_vec()); // First if branch is revocation_key - input.witness.push(sig.serialize_der(&self.secp_ctx).to_vec()); - input.witness[0].push(SigHashType::All as u8); + if inputs.is_empty() { return txn_to_broadcast; } // Nothing to be done...probably a false positive/local tx + + let outputs = vec!(TxOut { + script_pubkey: self.destination_script.clone(), + value: total_value, //TODO: - fee + }); + let mut spend_tx = Transaction { + version: 2, + lock_time: 0, + input: inputs, + output: outputs, + }; + + let mut values_drain = values.drain(..); + let sighash_parts = bip143::SighashComponents::new(&spend_tx); + + 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()); } + + txn_to_broadcast.push(spend_tx); } } - - txn_to_broadcast.push(spend_tx); + } else { + //TODO: For each input check if its in our remote_htlc_outputs_on_chain map! } txn_to_broadcast } - fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) { - for tx in txn_matched { - if tx.input.len() != 1 { - // We currently only ever sign something spending a commitment or HTLC - // transaction with 1 input, so we can skip most transactions trivially. - continue; + fn broadcast_by_local_state(&self, local_tx: &LocalSignedTx) -> Vec { + let mut res = Vec::with_capacity(local_tx.htlc_outputs.len()); + + 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); + + htlc_timeout_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy + + htlc_timeout_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec()); + htlc_timeout_tx.input[0].witness[1].push(SigHashType::All as u8); + htlc_timeout_tx.input[0].witness.push(our_sig.serialize_der(&self.secp_ctx).to_vec()); + htlc_timeout_tx.input[0].witness[2].push(SigHashType::All as u8); + + htlc_timeout_tx.input[0].witness.push(Vec::new()); + htlc_timeout_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_vec()); + + res.push(htlc_timeout_tx); + } else { + if let Some(payment_preimage) = self.payment_preimages.get(&htlc.payment_hash) { + let mut htlc_success_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); + + htlc_success_tx.input[0].witness.push(Vec::new()); // First is the multisig dummy + + htlc_success_tx.input[0].witness.push(their_sig.serialize_der(&self.secp_ctx).to_vec()); + htlc_success_tx.input[0].witness[1].push(SigHashType::All as u8); + 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(chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &local_tx.a_htlc_key, &local_tx.b_htlc_key, &local_tx.revocation_key).into_vec()); + + res.push(htlc_success_tx); + } } + } + + res + } + + /// 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 { + let commitment_txid = tx.txid(); + if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { + if local_tx.txid == commitment_txid { + return self.broadcast_by_local_state(local_tx); + } + } + if let &Some(ref local_tx) = &self.prev_local_signed_commitment_tx { + if local_tx.txid == commitment_txid { + return self.broadcast_by_local_state(local_tx); + } + } + Vec::new() + } + fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface) { + for tx in txn_matched { for txin in tx.input.iter() { if self.funding_txo.is_none() || (txin.prev_hash == self.funding_txo.unwrap().0 && txin.prev_index == self.funding_txo.unwrap().1 as u32) { - for tx in self.check_spend_transaction(tx, height).iter() { + let mut txn = self.check_spend_remote_transaction(tx, height); + if txn.is_empty() { + txn = self.check_spend_local_transaction(tx, height); + } + for tx in txn.iter() { broadcaster.broadcast_transaction(tx); } } } } + if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx { + let mut needs_broadcast = false; + for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() { + if htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER { + if htlc.offered || self.payment_preimages.contains_key(&htlc.payment_hash) { + needs_broadcast = true; + } + } + } + + if needs_broadcast { + broadcaster.broadcast_transaction(&cur_local_tx.tx); + for tx in self.broadcast_by_local_state(&cur_local_tx) { + broadcaster.broadcast_transaction(&tx); + } + } + } + } + + pub 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() { + if htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER { + if htlc.offered || self.payment_preimages.contains_key(&htlc.payment_hash) { + return true; + } + } + } + } + false } } @@ -498,336 +821,338 @@ mod tests { { // insert_secret correct sequence - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap()); - monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap()); - monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap()); - monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); } { // insert_secret #1 incorrect - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #2 incorrect (#1 derived from incorrect) - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #3 incorrect - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #4 incorrect (1,2,3 derived from incorrect) - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("02a40c85b6f28da08dfdbe0926c53fab2de6d28c10301f8f7c4073d5e42e3148").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("dddc3a8d14fddf2b68fa8c7fbad2748274937479dd0f8930d5ebb4ab6bd866a3").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c51a18b13e8527e579ec56365482c62f180b7d5760b46e9477dae59e87ed423a").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("ba65d7b0ef55a3ba300d4e87af29868f394f8f138d78a7011669c79b37b936f4").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap()); - monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap()); - monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap()); - assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #5 incorrect - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap()); - assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #6 incorrect (5 derived from incorrect) - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("631373ad5f9ef654bb3dade742d09504c567edd24320d2fcd68e3cc47e2ff6a6").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("b7e76a83668bde38b373970155c868a653304308f9896692f904a23731224bb1").unwrap()); - monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap()); - monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap()); - assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #7 incorrect - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap()); - monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("e7971de736e01da8ed58b94c2fc216cb1dca9e326f3a96e7194fe8ea8af6c0a3").unwrap()); - monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("05cde6323d949933f7f7b78776bcc1ea6d9b31447732e3802e1f7ac44b650e17").unwrap()); - assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } { // insert_secret #8 incorrect - monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &PublicKey::new(), 0, Script::new()); + monitor = ChannelMonitor::new(&SecretKey::from_slice(&secp_ctx, &[42; 32]).unwrap(), &PublicKey::new(), &SecretKey::from_slice(&secp_ctx, &[43; 32]).unwrap(), 0, Script::new()); secrets.clear(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); - monitor.provide_secret(281474976710655, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710655, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); - monitor.provide_secret(281474976710654, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710654, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); - monitor.provide_secret(281474976710653, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710653, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); - monitor.provide_secret(281474976710652, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710652, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("c65716add7aa98ba7acb236352d665cab17345fe45b55fb879ff80e6bd0c41dd").unwrap()); - monitor.provide_secret(281474976710651, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710651, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("969660042a28f32d9be17344e09374b379962d03db1574df5a8a5a47e19ce3f2").unwrap()); - monitor.provide_secret(281474976710650, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710650, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a5a64476122ca0925fb344bdc1854c1c0a59fc614298e50a33e331980a220f32").unwrap()); - monitor.provide_secret(281474976710649, secrets.last().unwrap().clone()).unwrap(); + monitor.provide_secret(281474976710649, secrets.last().unwrap().clone(), None).unwrap(); test_secrets!(); secrets.push([0; 32]); secrets.last_mut().unwrap()[0..32].clone_from_slice(&hex_bytes("a7efbc61aac46d34f77778bac22c8a20c6a46ca460addc49009bda875ec88fa4").unwrap()); - assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone()).unwrap_err().err, + assert_eq!(monitor.provide_secret(281474976710648, secrets.last().unwrap().clone(), None).unwrap_err().err, "Previous secret did not match new one"); } } + + // Further testing is done in the ChannelManager integration tests. } diff --git a/src/util/test_utils.rs b/src/util/test_utils.rs index 7e28f543..4502bcce 100644 --- a/src/util/test_utils.rs +++ b/src/util/test_utils.rs @@ -1,7 +1,6 @@ use chain::chaininterface; use chain::chaininterface::ConfirmationTarget; use ln::channelmonitor; -use ln::msgs::HandleError; use bitcoin::blockdata::transaction::Transaction; use bitcoin::util::hash::Sha256dHash; @@ -30,7 +29,7 @@ impl TestChannelMonitor { } } impl channelmonitor::ManyChannelMonitor for TestChannelMonitor { - fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: channelmonitor::ChannelMonitor) -> Result<(), HandleError> { + fn add_update_monitor(&self, funding_txo: (Sha256dHash, u16), monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { self.added_monitors.lock().unwrap().push((funding_txo, monitor.clone())); self.simple_monitor.add_update_monitor(funding_txo, monitor) } -- 2.30.2