X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=738fff3837ca045f5c8c9e3e93e588bb88974191;hb=b20aea1cb0fb9f19c646e96518ef9845e6593264;hp=e6f6ceda2b0b16f712963843a23fe4a478490f29;hpb=c931380cbc76bfa0bab6b039f0de15474faddef9;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index e6f6ceda..738fff38 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -20,7 +20,7 @@ //! security-domain-separated system design, you should consider having multiple paths for //! ChannelMonitors to get out of the HSM and onto monitoring devices. -use bitcoin::blockdata::block::{Block, BlockHeader}; +use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::transaction::{TxOut,Transaction}; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; @@ -29,8 +29,8 @@ use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; -use bitcoin::secp256k1::{Secp256k1,Signature}; -use bitcoin::secp256k1::key::{SecretKey,PublicKey}; +use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature}; +use bitcoin::secp256k1::{SecretKey, PublicKey}; use bitcoin::secp256k1; use ln::{PaymentHash, PaymentPreimage}; @@ -59,7 +59,7 @@ use sync::Mutex; /// An update generated by the underlying Channel itself which contains some new information the /// ChannelMonitor should be made aware of. -#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))] +#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] #[must_use] pub struct ChannelMonitorUpdate { @@ -441,7 +441,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent, ); -#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))] +#[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] pub(crate) enum ChannelMonitorUpdateStep { LatestHolderCommitmentTXInfo { @@ -473,6 +473,19 @@ pub(crate) enum ChannelMonitorUpdateStep { }, } +impl ChannelMonitorUpdateStep { + fn variant_name(&self) -> &'static str { + match self { + ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. } => "LatestHolderCommitmentTXInfo", + ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } => "LatestCounterpartyCommitmentTXInfo", + ChannelMonitorUpdateStep::PaymentPreimage { .. } => "PaymentPreimage", + ChannelMonitorUpdateStep::CommitmentSecret { .. } => "CommitmentSecret", + ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed", + ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript", + } + } +} + impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, (0, LatestHolderCommitmentTXInfo) => { (0, commitment_tx, required), @@ -711,9 +724,9 @@ pub(crate) struct ChannelMonitorImpl { /// Transaction outputs to watch for on-chain spends. pub type TransactionOutputs = (Txid, Vec<(u32, TxOut)>); -#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] -/// Used only in testing and fuzztarget to check serialization roundtrips don't change the -/// underlying object +#[cfg(any(test, fuzzing, feature = "_test_utils"))] +/// Used only in testing and fuzzing to check serialization roundtrips don't change the underlying +/// object impl PartialEq for ChannelMonitor { fn eq(&self, other: &Self) -> bool { let inner = self.inner.lock().unwrap(); @@ -722,9 +735,9 @@ impl PartialEq for ChannelMonitor { } } -#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] -/// Used only in testing and fuzztarget to check serialization roundtrips don't change the -/// underlying object +#[cfg(any(test, fuzzing, feature = "_test_utils"))] +/// Used only in testing and fuzzing to check serialization roundtrips don't change the underlying +/// object impl PartialEq for ChannelMonitorImpl { fn eq(&self, other: &Self) -> bool { if self.latest_update_id != other.latest_update_id || @@ -1379,8 +1392,23 @@ impl ChannelMonitor { ($holder_commitment: expr, $htlc_iter: expr) => { for htlc in $htlc_iter { if let Some(htlc_input_idx) = htlc.transaction_output_index { - if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) { - assert!(us.funding_spend_confirmed.is_some()); + if let Some(conf_thresh) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { + if let OnchainEvent::MaturingOutput { descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) } = &event.event { + if descriptor.outpoint.index as u32 == htlc_input_idx { Some(event.confirmation_threshold()) } else { None } + } else { None } + }) { + debug_assert!($holder_commitment); + res.push(Balance::ClaimableAwaitingConfirmations { + claimable_amount_satoshis: htlc.amount_msat / 1000, + confirmation_height: conf_thresh, + }); + } else if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) { + // Funding transaction spends should be fully confirmed by the time any + // HTLC transactions are resolved, unless we're talking about a holder + // commitment tx, whose resolution is delayed until the CSV timeout is + // reached, even though HTLCs may be resolved after only + // ANTI_REORG_DELAY confirmations. + debug_assert!($holder_commitment || us.funding_spend_confirmed.is_some()); } else if htlc.offered == $holder_commitment { // If the payment was outbound, check if there's an HTLCUpdate // indicating we have spent this HTLC with a timeout, claiming it back @@ -1871,16 +1899,21 @@ impl ChannelMonitorImpl { F::Target: FeeEstimator, L::Target: Logger, { + log_info!(logger, "Applying update to monitor {}, bringing update_id from {} to {} with {} changes.", + log_funding_info!(self), self.latest_update_id, updates.update_id, updates.updates.len()); // ChannelMonitor updates may be applied after force close if we receive a // preimage for a broadcasted commitment transaction HTLC output that we'd // like to claim on-chain. If this is the case, we no longer have guaranteed // access to the monitor's update ID, so we use a sentinel value instead. if updates.update_id == CLOSED_CHANNEL_UPDATE_ID { + assert_eq!(updates.updates.len(), 1); match updates.updates[0] { ChannelMonitorUpdateStep::PaymentPreimage { .. } => {}, - _ => panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"), + _ => { + log_error!(logger, "Attempted to apply post-force-close ChannelMonitorUpdate of type {}", updates.updates[0].variant_name()); + panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"); + }, } - assert_eq!(updates.updates.len(), 1); } else if self.latest_update_id + 1 != updates.update_id { panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!"); } @@ -2620,7 +2653,7 @@ impl ChannelMonitorImpl { // appears to be spending the correct type (ie that the match would // actually succeed in BIP 158/159-style filters). if _script_pubkey.is_v0_p2wsh() { - assert_eq!(&bitcoin::Address::p2wsh(&Script::from(input.witness.last().unwrap().clone()), bitcoin::Network::Bitcoin).script_pubkey(), _script_pubkey); + assert_eq!(&bitcoin::Address::p2wsh(&Script::from(input.witness.last().unwrap().to_vec()), bitcoin::Network::Bitcoin).script_pubkey(), _script_pubkey); } else if _script_pubkey.is_v0_p2wpkh() { assert_eq!(&bitcoin::Address::p2wpkh(&bitcoin::PublicKey::from_slice(&input.witness.last().unwrap()).unwrap(), bitcoin::Network::Bitcoin).unwrap().script_pubkey(), _script_pubkey); } else { panic!(); } @@ -2703,20 +2736,23 @@ impl ChannelMonitorImpl { fn is_resolving_htlc_output(&mut self, tx: &Transaction, height: u32, logger: &L) where L::Target: Logger { 'outer_loop: for input in &tx.input { let mut payment_data = None; - let revocation_sig_claim = (input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC) && input.witness[1].len() == 33) - || (input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::AcceptedHTLC) && input.witness[1].len() == 33); - let accepted_preimage_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[4].len()) == Some(HTLCType::AcceptedHTLC); + let witness_items = input.witness.len(); + let htlctype = input.witness.last().map(|w| w.len()).and_then(HTLCType::scriptlen_to_htlctype); + let prev_last_witness_len = input.witness.second_to_last().map(|w| w.len()).unwrap_or(0); + let revocation_sig_claim = (witness_items == 3 && htlctype == Some(HTLCType::OfferedHTLC) && prev_last_witness_len == 33) + || (witness_items == 3 && htlctype == Some(HTLCType::AcceptedHTLC) && prev_last_witness_len == 33); + let accepted_preimage_claim = witness_items == 5 && htlctype == Some(HTLCType::AcceptedHTLC); #[cfg(not(fuzzing))] - let accepted_timeout_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::AcceptedHTLC) && !revocation_sig_claim; - let offered_preimage_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC) && !revocation_sig_claim; + let accepted_timeout_claim = witness_items == 3 && htlctype == Some(HTLCType::AcceptedHTLC) && !revocation_sig_claim; + let offered_preimage_claim = witness_items == 3 && htlctype == Some(HTLCType::OfferedHTLC) && !revocation_sig_claim; #[cfg(not(fuzzing))] - let offered_timeout_claim = input.witness.len() == 5 && HTLCType::scriptlen_to_htlctype(input.witness[4].len()) == Some(HTLCType::OfferedHTLC); + let offered_timeout_claim = witness_items == 5 && htlctype == Some(HTLCType::OfferedHTLC); let mut payment_preimage = PaymentPreimage([0; 32]); if accepted_preimage_claim { - payment_preimage.0.copy_from_slice(&input.witness[3]); + payment_preimage.0.copy_from_slice(input.witness.second_to_last().unwrap()); } else if offered_preimage_claim { - payment_preimage.0.copy_from_slice(&input.witness[1]); + payment_preimage.0.copy_from_slice(input.witness.second_to_last().unwrap()); } macro_rules! log_claim { @@ -2974,9 +3010,8 @@ where F::Target: FeeEstimator, L::Target: Logger, { - fn block_connected(&self, block: &Block, height: u32) { - let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); - self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3); + fn filtered_block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) { + self.0.block_connected(header, txdata, height, &*self.1, &*self.2, &*self.3); } fn block_disconnected(&self, header: &BlockHeader, height: u32) { @@ -3290,15 +3325,15 @@ mod tests { use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; - use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType}; + use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, EcdsaSighashType}; use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; - use bitcoin::util::bip143; + use bitcoin::util::sighash; use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::{BlockHash, Txid}; use bitcoin::network::constants::Network; - use bitcoin::secp256k1::key::{SecretKey,PublicKey}; + use bitcoin::secp256k1::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use hex; @@ -3323,6 +3358,7 @@ mod tests { use util::ser::{ReadableArgs, Writeable}; use sync::{Arc, Mutex}; use io; + use bitcoin::Witness; use prelude::*; fn do_test_funding_spend_refuses_updates(use_local_txn: bool) { @@ -3576,24 +3612,27 @@ mod tests { transaction_output_index: Some($idx as u32), }; let redeem_script = if *$weight == WEIGHT_REVOKED_OUTPUT { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, $opt_anchors, &pubkey, &pubkey, &pubkey) }; - let sighash = hash_to_message!(&$sighash_parts.signature_hash($idx, &redeem_script, $amount, SigHashType::All)[..]); - let sig = secp_ctx.sign(&sighash, &privkey); - $sighash_parts.access_witness($idx).push(sig.serialize_der().to_vec()); - $sighash_parts.access_witness($idx)[0].push(SigHashType::All as u8); - $sum_actual_sigs += $sighash_parts.access_witness($idx)[0].len(); + let sighash = hash_to_message!(&$sighash_parts.segwit_signature_hash($idx, &redeem_script, $amount, EcdsaSighashType::All).unwrap()[..]); + let sig = secp_ctx.sign_ecdsa(&sighash, &privkey); + let mut ser_sig = sig.serialize_der().to_vec(); + ser_sig.push(EcdsaSighashType::All as u8); + $sum_actual_sigs += ser_sig.len(); + let witness = $sighash_parts.witness_mut($idx).unwrap(); + witness.push(ser_sig); if *$weight == WEIGHT_REVOKED_OUTPUT { - $sighash_parts.access_witness($idx).push(vec!(1)); + witness.push(vec!(1)); } else if *$weight == weight_revoked_offered_htlc($opt_anchors) || *$weight == weight_revoked_received_htlc($opt_anchors) { - $sighash_parts.access_witness($idx).push(pubkey.clone().serialize().to_vec()); + witness.push(pubkey.clone().serialize().to_vec()); } else if *$weight == weight_received_htlc($opt_anchors) { - $sighash_parts.access_witness($idx).push(vec![0]); + witness.push(vec![0]); } else { - $sighash_parts.access_witness($idx).push(PaymentPreimage([1; 32]).0.to_vec()); + witness.push(PaymentPreimage([1; 32]).0.to_vec()); } - $sighash_parts.access_witness($idx).push(redeem_script.into_bytes()); - println!("witness[0] {}", $sighash_parts.access_witness($idx)[0].len()); - println!("witness[1] {}", $sighash_parts.access_witness($idx)[1].len()); - println!("witness[2] {}", $sighash_parts.access_witness($idx)[2].len()); + witness.push(redeem_script.into_bytes()); + let witness = witness.to_vec(); + println!("witness[0] {}", witness[0].len()); + println!("witness[1] {}", witness[1].len()); + println!("witness[2] {}", witness[2].len()); } } @@ -3612,24 +3651,24 @@ mod tests { }, script_sig: Script::new(), sequence: 0xfffffffd, - witness: Vec::new(), + witness: Witness::new(), }); } claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), value: 0, }); - let base_weight = claim_tx.get_weight(); + let base_weight = claim_tx.weight(); let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT, weight_revoked_offered_htlc(opt_anchors), weight_revoked_offered_htlc(opt_anchors), weight_revoked_received_htlc(opt_anchors)]; let mut inputs_total_weight = 2; // count segwit flags { - let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); inputs_total_weight += inp; } } - assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs)); + assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs)); } // Claim tx with 1 offered HTLCs, 3 received HTLCs @@ -3644,24 +3683,24 @@ mod tests { }, script_sig: Script::new(), sequence: 0xfffffffd, - witness: Vec::new(), + witness: Witness::new(), }); } claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), value: 0, }); - let base_weight = claim_tx.get_weight(); + let base_weight = claim_tx.weight(); let inputs_weight = vec![weight_offered_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors), weight_received_htlc(opt_anchors)]; let mut inputs_total_weight = 2; // count segwit flags { - let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); inputs_total_weight += inp; } } - assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs)); + assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.weight() + /* max_length_sig */ (73 * inputs_weight.len() - sum_actual_sigs)); } // Justice tx with 1 revoked HTLC-Success tx output @@ -3675,23 +3714,23 @@ mod tests { }, script_sig: Script::new(), sequence: 0xfffffffd, - witness: Vec::new(), + witness: Witness::new(), }); claim_tx.output.push(TxOut { script_pubkey: script_pubkey.clone(), value: 0, }); - let base_weight = claim_tx.get_weight(); + let base_weight = claim_tx.weight(); let inputs_weight = vec![WEIGHT_REVOKED_OUTPUT]; let mut inputs_total_weight = 2; // count segwit flags { - let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + let mut sighash_parts = sighash::SighashCache::new(&mut claim_tx); for (idx, inp) in inputs_weight.iter().enumerate() { sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs, opt_anchors); inputs_total_weight += inp; } } - assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_weight.len() - sum_actual_sigs)); + assert_eq!(base_weight + inputs_total_weight as usize, claim_tx.weight() + /* max_length_isg */ (73 * inputs_weight.len() - sum_actual_sigs)); } }