X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmonitor.rs;h=edf87da6c59eba8dfde6c76d6181f55aab21e73c;hb=27079e04d7b542058e48cafaf5c2e7114b3b8e15;hp=c8e6b8260adbc0ec35821a2464e26678a44d4fda;hpb=f0e9524e6d34d6a33aeb953ef0f7c1cbb12ef034;p=rust-lightning diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index c8e6b826..edf87da6 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -19,14 +19,14 @@ use bitcoin::blockdata::opcodes; use bitcoin::consensus::encode; use bitcoin::util::hash::BitcoinHash; -use bitcoin_hashes::Hash; -use bitcoin_hashes::sha256::Hash as Sha256; -use bitcoin_hashes::hash160::Hash as Hash160; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin::hashes::Hash; +use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::hashes::hash160::Hash as Hash160; +use bitcoin::hash_types::{Txid, BlockHash}; -use secp256k1::{Secp256k1,Signature}; -use secp256k1::key::{SecretKey,PublicKey}; -use secp256k1; +use bitcoin::secp256k1::{Secp256k1,Signature}; +use bitcoin::secp256k1::key::{SecretKey,PublicKey}; +use bitcoin::secp256k1; use ln::msgs::DecodeError; use ln::chan_utils; @@ -409,7 +409,7 @@ pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_ #[derive(Clone, PartialEq)] struct LocalSignedTx { /// txid of the transaction in tx, just used to make comparison faster - txid: Sha256dHash, + txid: Txid, revocation_key: PublicKey, a_htlc_key: PublicKey, b_htlc_key: PublicKey, @@ -443,7 +443,7 @@ pub(crate) enum InputMaterial { amount: u64, }, Funding { - channel_value: u64, + funding_redeemscript: Script, } } @@ -471,9 +471,9 @@ impl Writeable for InputMaterial { preimage.write(writer)?; writer.write_all(&byte_utils::be64_to_array(*amount))?; }, - &InputMaterial::Funding { ref channel_value } => { + &InputMaterial::Funding { ref funding_redeemscript } => { writer.write_all(&[3; 1])?; - channel_value.write(writer)?; + funding_redeemscript.write(writer)?; } } Ok(()) @@ -520,9 +520,8 @@ impl Readable for InputMaterial { } }, 3 => { - let channel_value = Readable::read(reader)?; InputMaterial::Funding { - channel_value + funding_redeemscript: Readable::read(reader)?, } } _ => return Err(DecodeError::InvalidValue), @@ -728,8 +727,8 @@ pub struct ChannelMonitor { keys: ChanSigner, funding_info: (OutPoint, Script), - current_remote_commitment_txid: Option, - prev_remote_commitment_txid: Option, + current_remote_commitment_txid: Option, + prev_remote_commitment_txid: Option, their_htlc_base_key: PublicKey, their_delayed_payment_base_key: PublicKey, @@ -742,13 +741,13 @@ pub struct ChannelMonitor { their_to_self_delay: u16, commitment_secrets: CounterpartyCommitmentSecrets, - remote_claimable_outpoints: HashMap>)>>, + remote_claimable_outpoints: HashMap>)>>, /// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain. /// Nor can we figure out their commitment numbers without the commitment transaction they are /// spending. Thus, in order to claim them via revocation key, we track all the remote /// commitment transactions which we find on-chain, mapping them to the commitment number which /// can be used to derive the revocation key and claim the transactions. - remote_commitment_txn_on_chain: HashMap)>, + remote_commitment_txn_on_chain: HashMap)>, /// Cache used to make pruning of payment_preimages faster. /// Maps payment_hash values to commitment numbers for remote transactions for non-revoked /// remote transactions (ie should remain pretty small). @@ -783,22 +782,29 @@ pub struct ChannelMonitor { // interface knows about the TXOs that we want to be notified of spends of. We could probably // be smart and derive them from the above storage fields, but its much simpler and more // Obviously Correct (tm) if we just keep track of them explicitly. - outputs_to_watch: HashMap>, + outputs_to_watch: HashMap>, #[cfg(test)] pub onchain_tx_handler: OnchainTxHandler, #[cfg(not(test))] onchain_tx_handler: OnchainTxHandler, - // Used to detect programming bug due to unsafe monitor update sequence { ChannelForceClosed, LatestLocalCommitmentTXInfo } + // This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the + // channel has been force-closed. After this is set, no further local commitment transaction + // updates may occur, and we panic!() if one is provided. lockdown_from_offchain: bool, + // Set once we've signed a local commitment transaction and handed it over to our + // OnchainTxHandler. After this is set, no future updates to our local commitment transactions + // may occur, and we fail any such monitor updates. + local_tx_signed: bool, + // We simply modify last_block_hash in Channel's block_connected so that serialization is // consistent but hopefully the users' copy handles block_connected in a consistent way. // (we do *not*, however, update them in update_monitor to ensure any local user copies keep // their last_block_hash from its state and not based on updated copies that didn't run through // the full block_connected). - pub(crate) last_block_hash: Sha256dHash, + pub(crate) last_block_hash: BlockHash, secp_ctx: Secp256k1, //TODO: dedup this a bit... logger: Arc, } @@ -836,7 +842,9 @@ impl PartialEq for ChannelMonitor { self.pending_htlcs_updated != other.pending_htlcs_updated || self.pending_events.len() != other.pending_events.len() || // We trust events to round-trip properly self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf || - self.outputs_to_watch != other.outputs_to_watch + self.outputs_to_watch != other.outputs_to_watch || + self.lockdown_from_offchain != other.lockdown_from_offchain || + self.local_tx_signed != other.local_tx_signed { false } else { @@ -1037,6 +1045,7 @@ impl ChannelMonitor { self.onchain_tx_handler.write(writer)?; self.lockdown_from_offchain.write(writer)?; + self.local_tx_signed.write(writer)?; Ok(()) } @@ -1057,8 +1066,8 @@ impl ChannelMonitor { let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay, logger.clone()); - let local_tx_sequence = initial_local_commitment_tx.without_valid_witness().input[0].sequence as u64; - let local_tx_locktime = initial_local_commitment_tx.without_valid_witness().lock_time as u64; + let local_tx_sequence = initial_local_commitment_tx.unsigned_tx.input[0].sequence as u64; + let local_tx_locktime = initial_local_commitment_tx.unsigned_tx.lock_time as u64; let local_commitment_tx = LocalSignedTx { txid: initial_local_commitment_tx.txid(), revocation_key: initial_local_commitment_tx.local_keys.revocation_key, @@ -1119,6 +1128,7 @@ impl ChannelMonitor { onchain_tx_handler, lockdown_from_offchain: false, + local_tx_signed: false, last_block_hash: Default::default(), secp_ctx: Secp256k1::new(), @@ -1235,9 +1245,12 @@ impl ChannelMonitor { /// up-to-date as our local commitment transaction is updated. /// Panics if set_their_to_self_delay has never been called. pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>) -> Result<(), MonitorUpdateError> { + if self.local_tx_signed { + return Err(MonitorUpdateError("A local commitment tx has already been signed, no new local commitment txn can be sent to our counterparty")); + } let txid = commitment_tx.txid(); - let sequence = commitment_tx.without_valid_witness().input[0].sequence as u64; - let locktime = commitment_tx.without_valid_witness().lock_time as u64; + let sequence = commitment_tx.unsigned_tx.input[0].sequence as u64; + let locktime = commitment_tx.unsigned_tx.lock_time as u64; let mut new_local_commitment_tx = LocalSignedTx { txid, revocation_key: commitment_tx.local_keys.revocation_key, @@ -1350,7 +1363,7 @@ impl ChannelMonitor { /// Gets a list of txids, with their output scripts (in the order they appear in the /// transaction), which we must learn about spends of via block_connected(). - pub fn get_outputs_to_watch(&self) -> &HashMap> { + pub fn get_outputs_to_watch(&self) -> &HashMap> { &self.outputs_to_watch } @@ -1358,7 +1371,7 @@ impl ChannelMonitor { /// Generally useful when deserializing as during normal operation the return values of /// block_connected are sufficient to ensure all relevant outpoints are being monitored (note /// that the get_funding_txo outpoint and transaction must also be monitored for!). - pub fn get_monitored_outpoints(&self) -> Vec<(Sha256dHash, u32, &Script)> { + pub fn get_monitored_outpoints(&self) -> Vec<(Txid, u32, &Script)> { let mut res = Vec::with_capacity(self.remote_commitment_txn_on_chain.len() * 2); for (ref txid, &(_, ref outputs)) in self.remote_commitment_txn_on_chain.iter() { for (idx, output) in outputs.iter().enumerate() { @@ -1411,7 +1424,7 @@ impl ChannelMonitor { /// HTLC-Success/HTLC-Timeout transactions. /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of /// revoked remote commitment tx - fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Sha256dHash, Vec)) { + fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Txid, 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 claimable_outpoints = Vec::new(); @@ -1624,7 +1637,7 @@ impl ChannelMonitor { } /// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key - fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> (Vec, Option<(Sha256dHash, Vec)>) { + fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32) -> (Vec, Option<(Txid, Vec)>) { let htlc_txid = tx.txid(); if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 { return (Vec::new(), None) @@ -1664,8 +1677,18 @@ impl ChannelMonitor { for &(ref htlc, _, _) in local_tx.htlc_outputs.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) { Some(*preimage) } else { None }; - claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: local_tx.txid, vout: transaction_output_index as u32 }, witness_data: InputMaterial::LocalHTLC { preimage, amount: htlc.amount_msat / 1000 }}); + claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: local_tx.txid, vout: transaction_output_index as u32 }, + witness_data: InputMaterial::LocalHTLC { + preimage: if !htlc.offered { + if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) { + Some(preimage.clone()) + } else { + // We can't build an HTLC-Success transaction without the preimage + continue; + } + } else { None }, + amount: htlc.amount_msat, + }}); watch_outputs.push(commitment_tx.output[transaction_output_index as usize].clone()); } } @@ -1676,7 +1699,7 @@ impl ChannelMonitor { /// 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(&mut self, tx: &Transaction, height: u32) -> (Vec, (Sha256dHash, Vec)) { + fn check_spend_local_transaction(&mut self, tx: &Transaction, height: u32) -> (Vec, (Txid, Vec)) { let commitment_txid = tx.txid(); let mut claim_requests = Vec::new(); let mut watch_outputs = Vec::new(); @@ -1762,13 +1785,20 @@ impl ChannelMonitor { /// In any-case, choice is up to the user. pub fn get_latest_local_commitment_txn(&mut self) -> Vec { log_trace!(self, "Getting signed latest local commitment transaction!"); - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx() { + self.local_tx_signed = true; + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) { let txid = commitment_tx.txid(); let mut res = vec![commitment_tx]; for htlc in self.current_local_commitment_tx.htlc_outputs.iter() { - if let Some(htlc_index) = htlc.0.transaction_output_index { - let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) { + if let Some(vout) = htlc.0.transaction_output_index { + let preimage = if !htlc.0.offered { + if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { + // We can't build an HTLC-Success transaction without the preimage + continue; + } + } else { None }; + if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx( + &::bitcoin::OutPoint { txid, vout }, &preimage) { res.push(htlc_tx); } } @@ -1786,13 +1816,19 @@ impl ChannelMonitor { #[cfg(test)] pub fn unsafe_get_latest_local_commitment_txn(&mut self) -> Vec { log_trace!(self, "Getting signed copy of latest local commitment transaction!"); - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx() { + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(&self.funding_redeemscript) { let txid = commitment_tx.txid(); let mut res = vec![commitment_tx]; for htlc in self.current_local_commitment_tx.htlc_outputs.iter() { - if let Some(htlc_index) = htlc.0.transaction_output_index { - let preimage = if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(*preimage) } else { None }; - if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(txid, htlc_index, preimage) { + if let Some(vout) = htlc.0.transaction_output_index { + let preimage = if !htlc.0.offered { + if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { + // We can't build an HTLC-Success transaction without the preimage + continue; + } + } else { None }; + if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx( + &::bitcoin::OutPoint { txid, vout }, &preimage) { res.push(htlc_tx); } } @@ -1807,7 +1843,7 @@ impl ChannelMonitor { /// Eventually this should be pub and, roughly, implement ChainListener, however this requires /// &mut self, as well as returns new spendable outputs and outpoints to watch for spending of /// on-chain. - fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: B, fee_estimator: F)-> Vec<(Sha256dHash, Vec)> + fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F)-> Vec<(Txid, Vec)> where B::Target: BroadcasterInterface, F::Target: FeeEstimator { @@ -1864,10 +1900,10 @@ impl ChannelMonitor { } let should_broadcast = self.would_broadcast_at_height(height); if should_broadcast { - claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { channel_value: self.channel_value_satoshis }}); + claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }}); } if should_broadcast { - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx() { + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) { let (mut new_outpoints, new_outputs, _) = self.broadcast_by_local_state(&commitment_tx, &self.current_local_commitment_tx); if !new_outputs.is_empty() { watch_outputs.push((self.current_local_commitment_tx.txid.clone(), new_outputs)); @@ -1905,7 +1941,7 @@ impl ChannelMonitor { watch_outputs } - fn block_disconnected(&mut self, height: u32, block_hash: &Sha256dHash, broadcaster: B, fee_estimator: F) + fn block_disconnected(&mut self, height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F) where B::Target: BroadcasterInterface, F::Target: FeeEstimator { @@ -2174,7 +2210,7 @@ impl ChannelMonitor { const MAX_ALLOC_SIZE: usize = 64*1024; -impl ReadableArgs> for (Sha256dHash, ChannelMonitor) { +impl ReadableArgs> for (BlockHash, ChannelMonitor) { fn read(reader: &mut R, logger: Arc) -> Result { macro_rules! unwrap_obj { ($key: expr) => { @@ -2271,7 +2307,7 @@ impl ReadableArgs> for (Sha256dH let remote_claimable_outpoints_len: u64 = Readable::read(reader)?; let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64)); for _ in 0..remote_claimable_outpoints_len { - let txid: Sha256dHash = Readable::read(reader)?; + let txid: Txid = Readable::read(reader)?; let htlcs_count: u64 = Readable::read(reader)?; let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..htlcs_count { @@ -2285,7 +2321,7 @@ impl ReadableArgs> for (Sha256dH let remote_commitment_txn_on_chain_len: u64 = Readable::read(reader)?; let mut remote_commitment_txn_on_chain = HashMap::with_capacity(cmp::min(remote_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..remote_commitment_txn_on_chain_len { - let txid: Sha256dHash = Readable::read(reader)?; + let txid: Txid = Readable::read(reader)?; let commitment_number = ::read(reader)?.0; let outputs_count = ::read(reader)?; let mut outputs = Vec::with_capacity(cmp::min(outputs_count as usize, MAX_ALLOC_SIZE / 8)); @@ -2375,7 +2411,7 @@ impl ReadableArgs> for (Sha256dH } } - let last_block_hash: Sha256dHash = Readable::read(reader)?; + let last_block_hash: BlockHash = Readable::read(reader)?; let waiting_threshold_conf_len: u64 = Readable::read(reader)?; let mut onchain_events_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128)); @@ -2406,7 +2442,7 @@ impl ReadableArgs> for (Sha256dH } let outputs_to_watch_len: u64 = Readable::read(reader)?; - let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::() + mem::size_of::>()))); + let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::() + mem::size_of::>()))); for _ in 0..outputs_to_watch_len { let txid = Readable::read(reader)?; let outputs_len: u64 = Readable::read(reader)?; @@ -2421,6 +2457,7 @@ impl ReadableArgs> for (Sha256dH let onchain_tx_handler = ReadableArgs::read(reader, logger.clone())?; let lockdown_from_offchain = Readable::read(reader)?; + let local_tx_signed = Readable::read(reader)?; Ok((last_block_hash.clone(), ChannelMonitor { latest_update_id, @@ -2465,6 +2502,7 @@ impl ReadableArgs> for (Sha256dH onchain_tx_handler, lockdown_from_offchain, + local_tx_signed, last_block_hash, secp_ctx: Secp256k1::new(), @@ -2480,10 +2518,10 @@ mod tests { use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType}; use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; use bitcoin::util::bip143; - use bitcoin_hashes::Hash; - use bitcoin_hashes::sha256::Hash as Sha256; - use bitcoin_hashes::sha256d::Hash as Sha256dHash; - use bitcoin_hashes::hex::FromHex; + use bitcoin::hashes::Hash; + use bitcoin::hashes::sha256::Hash as Sha256; + use bitcoin::hashes::hex::FromHex; + use bitcoin::hash_types::Txid; use hex; use chain::transaction::OutPoint; use ln::channelmanager::{PaymentPreimage, PaymentHash}; @@ -2492,8 +2530,8 @@ mod tests { use ln::chan_utils; use ln::chan_utils::{HTLCOutputInCommitment, LocalCommitmentTransaction}; use util::test_utils::TestLogger; - use secp256k1::key::{SecretKey,PublicKey}; - use secp256k1::Secp256k1; + use bitcoin::secp256k1::key::{SecretKey,PublicKey}; + use bitcoin::secp256k1::Secp256k1; use rand::{thread_rng,Rng}; use std::sync::Arc; use chain::keysinterface::InMemoryChannelKeys; @@ -2567,7 +2605,7 @@ mod tests { // old state. let mut monitor = ChannelMonitor::new(keys, &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(), - (OutPoint { txid: Sha256dHash::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()), + (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[44; 32]).unwrap()), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap()), 10, Script::new(), 46, 0, LocalCommitmentTransaction::dummy(), logger.clone()); @@ -2655,7 +2693,7 @@ mod tests { } let script_pubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(); - let txid = Sha256dHash::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap(); + let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap(); // Justice tx with 1 to_local, 2 revoked offered HTLCs, 1 revoked received HTLCs let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };