X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannelmonitor.rs;h=13cdfd2fe5d75433c5c28db097af4c12c0965de1;hb=608cf1c89db01f9cf612516a88a3f77f1f48bc52;hp=fd970e8b387447c8f284d174eae2c817c2929ca2;hpb=f5ccd4b4ef6c089c7138615cd3d5a2b664144a5c;p=rust-lightning diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index fd970e8b..13cdfd2f 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -17,10 +17,12 @@ use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::consensus::encode::{self, Decodable, Encodable}; -use bitcoin::util::hash::{Hash160, BitcoinHash,Sha256dHash}; +use bitcoin::util::hash::{BitcoinHash,Sha256dHash}; use bitcoin::util::bip143; -use crypto::digest::Digest; +use bitcoin_hashes::Hash; +use bitcoin_hashes::sha256::Hash as Sha256; +use bitcoin_hashes::hash160::Hash as Hash160; use secp256k1::{Secp256k1,Message,Signature}; use secp256k1::key::{SecretKey,PublicKey}; @@ -36,7 +38,6 @@ use chain::transaction::OutPoint; use chain::keysinterface::SpendableOutputDescriptor; use util::logger::Logger; use util::ser::{ReadableArgs, Readable, Writer, Writeable, WriterWriteAdaptor, U48}; -use util::sha2::Sha256; use util::{byte_utils, events}; use std::collections::{HashMap, hash_map}; @@ -295,6 +296,11 @@ pub(crate) const CLTV_CLAIM_BUFFER: u32 = 6; /// network and done a full update_fail_htlc/commitment_signed dance (+ we've updated all our /// copies of ChannelMonitors, including watchtowers). pub(crate) const HTLC_FAIL_TIMEOUT_BLOCKS: u32 = 3; +/// Number of blocks we wait on seeing a confirmed HTLC-Timeout or previous revoked commitment +/// transaction before we fail corresponding inbound HTLCs. This prevents us from failing backwards +/// and then getting a reorg resulting in us losing money. +//TODO: We currently dont actually use this...we should +pub(crate) const HTLC_FAIL_ANTI_REORG_DELAY: u32 = 6; #[derive(Clone, PartialEq)] enum Storage { @@ -482,9 +488,7 @@ impl ChannelMonitor { let bitpos = bits - 1 - i; if idx & (1 << bitpos) == (1 << bitpos) { res[(bitpos / 8) as usize] ^= 1 << (bitpos & 7); - let mut sha = Sha256::new(); - sha.input(&res); - sha.result(&mut res); + res = Sha256::hash(&res).into_inner(); } } res @@ -564,6 +568,8 @@ impl ChannelMonitor { } let new_txid = unsigned_commitment_tx.txid(); + log_trace!(self, "Tracking new remote commitment transaction with txid {} at commitment number {} with {} HTLC outputs", new_txid, commitment_number, htlc_outputs.len()); + log_trace!(self, "New potential remote commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx)); if let Storage::Local { ref mut current_remote_commitment_txid, ref mut prev_remote_commitment_txid, .. } = self.key_storage { *prev_remote_commitment_txid = current_remote_commitment_txid.take(); *current_remote_commitment_txid = Some(new_txid); @@ -983,9 +989,6 @@ impl ChannelMonitor { self.write(writer, false) } - //TODO: Functions to serialize/deserialize (with different forms depending on which information - //we want to leave out (eg funding_txo, etc). - /// Can only fail if idx is < get_min_seen_secret pub(super) fn get_secret(&self, idx: u64) -> Option<[u8; 32]> { for i in 0..self.old_secrets.len() { @@ -1074,7 +1077,7 @@ impl ChannelMonitor { let local_payment_p2wpkh = if let Some(payment_key) = local_payment_key { // Note that the Network here is ignored as we immediately drop the address for the // script_pubkey version. - let payment_hash160 = Hash160::from_data(&PublicKey::from_secret_key(&self.secp_ctx, &payment_key).serialize()); + let payment_hash160 = Hash160::hash(&PublicKey::from_secret_key(&self.secp_ctx, &payment_key).serialize()); Some(Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()) } else { None }; @@ -1242,6 +1245,44 @@ impl ChannelMonitor { watch_outputs.append(&mut tx.output.clone()); self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); + log_trace!(self, "Got broadcast of non-revoked remote commitment transaction {}", commitment_txid); + + // TODO: We really should only fail backwards after our revocation claims have been + // confirmed, but we also need to do more other tracking of in-flight pre-confirm + // on-chain claims, so we can do that at the same time. + macro_rules! check_htlc_fails { + ($txid: expr, $commitment_tx: expr, $id: tt) => { + if let Some(&(_, ref latest_outpoints)) = self.remote_claimable_outpoints.get(&$txid) { + $id: for &(ref payment_hash, ref source, _) in latest_outpoints.iter() { + // Check if the HTLC is present in the commitment transaction that was + // broadcast, but not if it was below the dust limit, which we should + // fail backwards immediately as there is no way for us to learn the + // payment_preimage. + // Note that if the dust limit were allowed to change between + // commitment transactions we'd want to be check whether *any* + // broadcastable commitment transaction has the HTLC in it, but it + // cannot currently change after channel initialization, so we don't + // need to here. + for &(_, ref broadcast_source, ref output_idx) in per_commitment_data.1.iter() { + if output_idx.is_some() && source == broadcast_source { + continue $id; + } + } + log_trace!(self, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of remote commitment transaction", log_bytes!(payment_hash.0), $commitment_tx); + htlc_updated.push(((*source).clone(), None, payment_hash.clone())); + } + } + } + } + if let Storage::Local { ref current_remote_commitment_txid, ref prev_remote_commitment_txid, .. } = self.key_storage { + if let &Some(ref txid) = current_remote_commitment_txid { + check_htlc_fails!(txid, "current", 'current_loop); + } + if let &Some(ref txid) = prev_remote_commitment_txid { + check_htlc_fails!(txid, "previous", 'prev_loop); + } + } + if let Some(revocation_points) = self.their_cur_revocation_points { let revocation_point_option = if revocation_points.0 == commitment_number { Some(&revocation_points.1) } @@ -1573,6 +1614,9 @@ impl ChannelMonitor { /// Should not be used if check_spend_revoked_transaction succeeds. fn check_spend_local_transaction(&self, tx: &Transaction, _height: u32) -> (Vec, Vec, (Sha256dHash, Vec)) { let commitment_txid = tx.txid(); + // TODO: If we find a match here we need to fail back HTLCs that were't included in the + // broadcast commitment transaction, either because they didn't meet dust or because they + // weren't yet included in our commitment transaction(s). if let &Some(ref local_tx) = &self.current_local_signed_commitment_tx { if local_tx.txid == commitment_txid { match self.key_storage { @@ -1609,7 +1653,7 @@ impl ChannelMonitor { if tx.input[0].sequence == 0xFFFFFFFF && !tx.input[0].witness.is_empty() && tx.input[0].witness.last().unwrap().len() == 71 { match self.key_storage { Storage::Local { ref shutdown_pubkey, .. } => { - let our_channel_close_key_hash = Hash160::from_data(&shutdown_pubkey.serialize()); + let our_channel_close_key_hash = Hash160::hash(&shutdown_pubkey.serialize()); let shutdown_script = Builder::new().push_opcode(opcodes::All::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script(); for (idx, output) in tx.output.iter().enumerate() { if shutdown_script == output.script_pubkey { @@ -1741,6 +1785,16 @@ impl ChannelMonitor { } pub(super) fn would_broadcast_at_height(&self, height: u32) -> bool { + // TODO: We need to consider HTLCs which weren't included in latest local commitment + // transaction (or in any of the latest two local commitment transactions). This probably + // needs to use the same logic as the revoked-tx-announe logic - checking the last two + // remote commitment transactions. This probably has implications for what data we need to + // store in local commitment transactions. + // TODO: We need to consider HTLCs which were below dust threshold here - while they don't + // strictly imply that we need to fail the channel, we need to go ahead and fail them back + // to the source, and if we don't fail the channel we will have to ensure that the next + // updates that peer sends us are update_fails, failing the channel if not. It's probably + // easier to just fail the channel as this case should be rare enough anyway. if let Some(ref cur_local_tx) = self.current_local_signed_commitment_tx { for &(ref htlc, _, _) in cur_local_tx.htlc_outputs.iter() { // For inbound HTLCs which we know the preimage for, we have to ensure we hit the @@ -2076,13 +2130,9 @@ impl ReadableArgs> for (Sha256dHash, ChannelM let payment_preimages_len: u64 = Readable::read(reader)?; let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32)); - let mut sha = Sha256::new(); for _ in 0..payment_preimages_len { let preimage: PaymentPreimage = Readable::read(reader)?; - sha.reset(); - sha.input(&preimage.0[..]); - let mut hash = PaymentHash([0; 32]); - sha.result(&mut hash.0[..]); + let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner()); if let Some(_) = payment_preimages.insert(hash, preimage) { return Err(DecodeError::InvalidValue); } @@ -2126,12 +2176,12 @@ impl ReadableArgs> for (Sha256dHash, ChannelM mod tests { use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::Transaction; - use crypto::digest::Digest; + use bitcoin_hashes::Hash; + use bitcoin_hashes::sha256::Hash as Sha256; use hex; use ln::channelmanager::{PaymentPreimage, PaymentHash}; use ln::channelmonitor::ChannelMonitor; use ln::chan_utils::{HTLCOutputInCommitment, TxCreationKeys}; - use util::sha2::Sha256; use util::test_utils::TestLogger; use secp256k1::key::{SecretKey,PublicKey}; use secp256k1::{Secp256k1, Signature}; @@ -2522,10 +2572,7 @@ mod tests { for _ in 0..20 { let mut preimage = PaymentPreimage([0; 32]); rng.fill_bytes(&mut preimage.0[..]); - let mut sha = Sha256::new(); - sha.input(&preimage.0[..]); - let mut hash = PaymentHash([0; 32]); - sha.result(&mut hash.0[..]); + let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner()); preimages.push((preimage, hash)); } }