X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=5128600163a42854f0be6c2bb5f27f79608050e6;hb=997e75a65a98c6e72d6306d1a4d8c15bce5de095;hp=96caaad27636acdfe5ebc18044e9a74ff69ce080;hpb=acb4c539f7753efab69f430b84b6261e740d5d43;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 96caaad2..51286001 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}; @@ -166,11 +166,11 @@ pub struct HTLCUpdate { pub(crate) payment_hash: PaymentHash, pub(crate) payment_preimage: Option, pub(crate) source: HTLCSource, - pub(crate) onchain_value_satoshis: Option, + pub(crate) htlc_value_satoshis: Option, } impl_writeable_tlv_based!(HTLCUpdate, { (0, payment_hash, required), - (1, onchain_value_satoshis, option), + (1, htlc_value_satoshis, option), (2, source, required), (4, payment_preimage, option), }); @@ -357,10 +357,10 @@ enum OnchainEvent { HTLCUpdate { source: HTLCSource, payment_hash: PaymentHash, - onchain_value_satoshis: Option, + htlc_value_satoshis: Option, /// None in the second case, above, ie when there is no relevant output in the commitment /// transaction which appeared on chain. - input_idx: Option, + commitment_tx_output_idx: Option, }, MaturingOutput { descriptor: SpendableOutputDescriptor, @@ -381,7 +381,7 @@ enum OnchainEvent { /// * a revoked-state HTLC transaction was broadcasted, which was claimed by the revocation /// signature. HTLCSpendConfirmation { - input_idx: u32, + commitment_tx_output_idx: u32, /// If the claim was made by either party with a preimage, this is filled in preimage: Option, /// If the claim was made by us on an inbound HTLC against a local commitment transaction, @@ -423,9 +423,9 @@ impl MaybeReadable for OnchainEventEntry { impl_writeable_tlv_based_enum_upgradable!(OnchainEvent, (0, HTLCUpdate) => { (0, source, required), - (1, onchain_value_satoshis, option), + (1, htlc_value_satoshis, option), (2, payment_hash, required), - (3, input_idx, option), + (3, commitment_tx_output_idx, option), }, (1, MaturingOutput) => { (0, descriptor, required), @@ -434,7 +434,7 @@ impl_writeable_tlv_based_enum_upgradable!(OnchainEvent, (0, on_local_output_csv, option), }, (5, HTLCSpendConfirmation) => { - (0, input_idx, required), + (0, commitment_tx_output_idx, required), (2, preimage, option), (4, on_to_local_output_csv, option), }, @@ -452,7 +452,7 @@ pub(crate) enum ChannelMonitorUpdateStep { commitment_txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, - their_revocation_point: PublicKey, + their_per_commitment_point: PublicKey, }, PaymentPreimage { payment_preimage: PaymentPreimage, @@ -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), @@ -481,7 +494,7 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, (1, LatestCounterpartyCommitmentTXInfo) => { (0, commitment_txid, required), (2, commitment_number, required), - (4, their_revocation_point, required), + (4, their_per_commitment_point, required), (6, htlc_outputs, vec_type), }, (2, PaymentPreimage) => { @@ -555,13 +568,13 @@ pub enum Balance { /// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY. #[derive(PartialEq)] struct IrrevocablyResolvedHTLC { - input_idx: u32, + commitment_tx_output_idx: u32, /// Only set if the HTLC claim was ours using a payment preimage payment_preimage: Option, } impl_writeable_tlv_based!(IrrevocablyResolvedHTLC, { - (0, input_idx, required), + (0, commitment_tx_output_idx, required), (2, payment_preimage, option), }); @@ -606,8 +619,8 @@ pub(crate) struct ChannelMonitorImpl { counterparty_commitment_params: CounterpartyCommitmentParameters, funding_redeemscript: Script, channel_value_satoshis: u64, - // first is the idx of the first of the two revocation points - their_cur_revocation_points: Option<(u64, PublicKey, Option)>, + // first is the idx of the first of the two per-commitment points + their_cur_per_commitment_points: Option<(u64, PublicKey, Option)>, on_holder_tx_csv: u16, @@ -642,6 +655,10 @@ pub(crate) struct ChannelMonitorImpl { // deserialization current_holder_commitment_number: u64, + /// The set of payment hashes from inbound payments for which we know the preimage. Payment + /// preimages that are not included in any unrevoked local commitment transaction or unrevoked + /// remote commitment transactions are automatically removed when commitment transactions are + /// revoked. payment_preimages: HashMap, // Note that `MonitorEvent`s MUST NOT be generated during update processing, only generated @@ -740,7 +757,7 @@ impl PartialEq for ChannelMonitorImpl { self.counterparty_commitment_params != other.counterparty_commitment_params || self.funding_redeemscript != other.funding_redeemscript || self.channel_value_satoshis != other.channel_value_satoshis || - self.their_cur_revocation_points != other.their_cur_revocation_points || + self.their_cur_per_commitment_points != other.their_cur_per_commitment_points || self.on_holder_tx_csv != other.on_holder_tx_csv || self.commitment_secrets != other.commitment_secrets || self.counterparty_claimable_outpoints != other.counterparty_claimable_outpoints || @@ -815,7 +832,7 @@ impl Writeable for ChannelMonitorImpl { self.funding_redeemscript.write(writer)?; self.channel_value_satoshis.write(writer)?; - match self.their_cur_revocation_points { + match self.their_cur_per_commitment_points { Some((idx, pubkey, second_option)) => { writer.write_all(&byte_utils::be48_to_array(idx))?; writer.write_all(&pubkey.serialize())?; @@ -1007,7 +1024,7 @@ impl ChannelMonitor { counterparty_commitment_params, funding_redeemscript, channel_value_satoshis, - their_cur_revocation_points: None, + their_cur_per_commitment_points: None, on_holder_tx_csv: counterparty_channel_parameters.selected_contest_delay, @@ -1057,11 +1074,11 @@ impl ChannelMonitor { txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, - their_revocation_point: PublicKey, + their_per_commitment_point: PublicKey, logger: &L, ) where L::Target: Logger { self.inner.lock().unwrap().provide_latest_counterparty_commitment_tx( - txid, htlc_outputs, commitment_number, their_revocation_point, logger) + txid, htlc_outputs, commitment_number, their_per_commitment_point, logger) } #[cfg(test)] @@ -1072,7 +1089,8 @@ impl ChannelMonitor { self.inner.lock().unwrap().provide_latest_holder_commitment_tx(holder_commitment_tx, htlc_outputs).map_err(|_| ()) } - #[cfg(test)] + /// This is used to provide payment preimage(s) out-of-band during startup without updating the + /// off-chain state with a new commitment transaction. pub(crate) fn provide_payment_preimage( &self, payment_hash: &PaymentHash, @@ -1378,16 +1396,32 @@ impl ChannelMonitor { macro_rules! walk_htlcs { ($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(htlc_commitment_tx_output_idx) = htlc.transaction_output_index { + 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_commitment_tx_output_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.commitment_tx_output_idx == htlc_commitment_tx_output_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 // and awaiting confirmations on it. let htlc_update_pending = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { - if let OnchainEvent::HTLCUpdate { input_idx: Some(input_idx), .. } = event.event { - if input_idx == htlc_input_idx { Some(event.confirmation_threshold()) } else { None } + if let OnchainEvent::HTLCUpdate { commitment_tx_output_idx: Some(commitment_tx_output_idx), .. } = event.event { + if commitment_tx_output_idx == htlc_commitment_tx_output_idx { + Some(event.confirmation_threshold()) } else { None } } else { None } }); if let Some(conf_thresh) = htlc_update_pending { @@ -1408,8 +1442,8 @@ impl ChannelMonitor { // preimage, we lost funds to our counterparty! We will then continue // to show it as ContentiousClaimable until ANTI_REORG_DELAY. let htlc_spend_pending = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { - if let OnchainEvent::HTLCSpendConfirmation { input_idx, preimage, .. } = event.event { - if input_idx == htlc_input_idx { + if let OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } = event.event { + if commitment_tx_output_idx == htlc_commitment_tx_output_idx { Some((event.confirmation_threshold(), preimage.is_some())) } else { None } } else { None } @@ -1518,7 +1552,7 @@ impl ChannelMonitor { macro_rules! walk_htlcs { ($holder_commitment: expr, $htlc_iter: expr) => { for (htlc, source) in $htlc_iter { - if us.htlcs_resolved_on_chain.iter().any(|v| Some(v.input_idx) == htlc.transaction_output_index) { + if us.htlcs_resolved_on_chain.iter().any(|v| Some(v.commitment_tx_output_idx) == htlc.transaction_output_index) { // We should assert that funding_spend_confirmed is_some() here, but we // have some unit tests which violate HTLC transaction CSVs entirely and // would fail. @@ -1529,17 +1563,17 @@ impl ChannelMonitor { // indicating we have spent this HTLC with a timeout, claiming it back // and awaiting confirmations on it. let htlc_update_confd = us.onchain_events_awaiting_threshold_conf.iter().any(|event| { - if let OnchainEvent::HTLCUpdate { input_idx: Some(input_idx), .. } = event.event { + if let OnchainEvent::HTLCUpdate { commitment_tx_output_idx: Some(commitment_tx_output_idx), .. } = event.event { // If the HTLC was timed out, we wait for ANTI_REORG_DELAY blocks // before considering it "no longer pending" - this matches when we // provide the ChannelManager an HTLC failure event. - Some(input_idx) == htlc.transaction_output_index && + Some(commitment_tx_output_idx) == htlc.transaction_output_index && us.best_block.height() >= event.height + ANTI_REORG_DELAY - 1 - } else if let OnchainEvent::HTLCSpendConfirmation { input_idx, .. } = event.event { + } else if let OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, .. } = event.event { // If the HTLC was fulfilled with a preimage, we consider the HTLC // immediately non-pending, matching when we provide ChannelManager // the preimage. - Some(input_idx) == htlc.transaction_output_index + Some(commitment_tx_output_idx) == htlc.transaction_output_index } else { false } }); if !htlc_update_confd { @@ -1603,6 +1637,10 @@ impl ChannelMonitor { res } + + pub(crate) fn get_stored_preimages(&self) -> HashMap { + self.inner.lock().unwrap().payment_preimages.clone() + } } /// Compares a broadcasted commitment transaction's HTLCs with those in the latest state, @@ -1660,8 +1698,8 @@ macro_rules! fail_unbroadcast_htlcs { event: OnchainEvent::HTLCUpdate { source: (**source).clone(), payment_hash: htlc.payment_hash.clone(), - onchain_value_satoshis: Some(htlc.amount_msat / 1000), - input_idx: None, + htlc_value_satoshis: Some(htlc.amount_msat / 1000), + commitment_tx_output_idx: None, }, }; log_trace!($logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of {} commitment transaction, waiting for confirmation (at height {})", @@ -1733,7 +1771,7 @@ impl ChannelMonitorImpl { Ok(()) } - pub(crate) fn provide_latest_counterparty_commitment_tx(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, their_revocation_point: PublicKey, logger: &L) where L::Target: Logger { + pub(crate) fn provide_latest_counterparty_commitment_tx(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, their_per_commitment_point: PublicKey, logger: &L) where L::Target: Logger { // TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction // so that a remote monitor doesn't learn anything unless there is a malicious close. // (only maybe, sadly we cant do the same for local info, as we need to be aware of @@ -1748,22 +1786,22 @@ impl ChannelMonitorImpl { self.counterparty_claimable_outpoints.insert(txid, htlc_outputs.clone()); self.current_counterparty_commitment_number = commitment_number; //TODO: Merge this into the other per-counterparty-transaction output storage stuff - match self.their_cur_revocation_points { + match self.their_cur_per_commitment_points { Some(old_points) => { if old_points.0 == commitment_number + 1 { - self.their_cur_revocation_points = Some((old_points.0, old_points.1, Some(their_revocation_point))); + self.their_cur_per_commitment_points = Some((old_points.0, old_points.1, Some(their_per_commitment_point))); } else if old_points.0 == commitment_number + 2 { if let Some(old_second_point) = old_points.2 { - self.their_cur_revocation_points = Some((old_points.0 - 1, old_second_point, Some(their_revocation_point))); + self.their_cur_per_commitment_points = Some((old_points.0 - 1, old_second_point, Some(their_per_commitment_point))); } else { - self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); + self.their_cur_per_commitment_points = Some((commitment_number, their_per_commitment_point, None)); } } else { - self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); + self.their_cur_per_commitment_points = Some((commitment_number, their_per_commitment_point, None)); } }, None => { - self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); + self.their_cur_per_commitment_points = Some((commitment_number, their_per_commitment_point, None)); } } let mut htlcs = Vec::with_capacity(htlc_outputs.len()); @@ -1871,16 +1909,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!"); } @@ -1896,9 +1939,9 @@ impl ChannelMonitorImpl { ret = Err(()); } } - ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_revocation_point } => { + ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, htlc_outputs, commitment_number, their_per_commitment_point } => { log_trace!(logger, "Updating ChannelMonitor with latest counterparty commitment transaction info"); - self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_revocation_point, logger) + self.provide_latest_counterparty_commitment_tx(*commitment_txid, htlc_outputs.clone(), *commitment_number, *their_per_commitment_point, logger) }, ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => { log_trace!(logger, "Updating ChannelMonitor with payment preimage"); @@ -2087,18 +2130,18 @@ impl ChannelMonitorImpl { fn get_counterparty_htlc_output_claim_reqs(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>) -> Vec { let mut claimable_outpoints = Vec::new(); if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&commitment_txid) { - if let Some(revocation_points) = self.their_cur_revocation_points { - let revocation_point_option = + if let Some(per_commitment_points) = self.their_cur_per_commitment_points { + let per_commitment_point_option = // If the counterparty commitment tx is the latest valid state, use their latest // per-commitment point - if revocation_points.0 == commitment_number { Some(&revocation_points.1) } - else if let Some(point) = revocation_points.2.as_ref() { + if per_commitment_points.0 == commitment_number { Some(&per_commitment_points.1) } + else if let Some(point) = per_commitment_points.2.as_ref() { // If counterparty commitment tx is the state previous to the latest valid state, use // their previous per-commitment point (non-atomicity of revocation means it's valid for // them to temporarily have two valid commitment txns from our viewpoint) - if revocation_points.0 == commitment_number + 1 { Some(point) } else { None } + if per_commitment_points.0 == commitment_number + 1 { Some(point) } else { None } } else { None }; - if let Some(revocation_point) = revocation_point_option { + if let Some(per_commitment_point) = per_commitment_point_option { for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() { if let Some(transaction_output_index) = htlc.transaction_output_index { if let Some(transaction) = tx { @@ -2109,7 +2152,19 @@ impl ChannelMonitorImpl { } let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None }; if preimage.is_some() || !htlc.offered { - let counterparty_htlc_outp = if htlc.offered { PackageSolvingData::CounterpartyOfferedHTLCOutput(CounterpartyOfferedHTLCOutput::build(*revocation_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, preimage.unwrap(), htlc.clone())) } else { PackageSolvingData::CounterpartyReceivedHTLCOutput(CounterpartyReceivedHTLCOutput::build(*revocation_point, self.counterparty_commitment_params.counterparty_delayed_payment_base_key, self.counterparty_commitment_params.counterparty_htlc_base_key, htlc.clone())) }; + let counterparty_htlc_outp = if htlc.offered { + PackageSolvingData::CounterpartyOfferedHTLCOutput( + CounterpartyOfferedHTLCOutput::build(*per_commitment_point, + self.counterparty_commitment_params.counterparty_delayed_payment_base_key, + self.counterparty_commitment_params.counterparty_htlc_base_key, + preimage.unwrap(), htlc.clone())) + } else { + PackageSolvingData::CounterpartyReceivedHTLCOutput( + CounterpartyReceivedHTLCOutput::build(*per_commitment_point, + self.counterparty_commitment_params.counterparty_delayed_payment_base_key, + self.counterparty_commitment_params.counterparty_htlc_base_key, + htlc.clone())) + }; let aggregation = if !htlc.offered { false } else { true }; let counterparty_package = PackageTemplate::build_package(commitment_txid, transaction_output_index, counterparty_htlc_outp, htlc.cltv_expiry,aggregation, 0); claimable_outpoints.push(counterparty_package); @@ -2489,7 +2544,7 @@ impl ChannelMonitorImpl { // Produce actionable events from on-chain events having reached their threshold. for entry in onchain_events_reaching_threshold_conf.drain(..) { match entry.event { - OnchainEvent::HTLCUpdate { ref source, payment_hash, onchain_value_satoshis, input_idx } => { + OnchainEvent::HTLCUpdate { ref source, payment_hash, htlc_value_satoshis, commitment_tx_output_idx } => { // Check for duplicate HTLC resolutions. #[cfg(debug_assertions)] { @@ -2511,10 +2566,10 @@ impl ChannelMonitorImpl { payment_hash, payment_preimage: None, source: source.clone(), - onchain_value_satoshis, + htlc_value_satoshis, })); - if let Some(idx) = input_idx { - self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC { input_idx: idx, payment_preimage: None }); + if let Some(idx) = commitment_tx_output_idx { + self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC { commitment_tx_output_idx: idx, payment_preimage: None }); } }, OnchainEvent::MaturingOutput { descriptor } => { @@ -2523,8 +2578,8 @@ impl ChannelMonitorImpl { outputs: vec![descriptor] }); }, - OnchainEvent::HTLCSpendConfirmation { input_idx, preimage, .. } => { - self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC { input_idx, payment_preimage: preimage }); + OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } => { + self.htlcs_resolved_on_chain.push(IrrevocablyResolvedHTLC { commitment_tx_output_idx, payment_preimage: preimage }); }, OnchainEvent::FundingSpendConfirmation { .. } => { self.funding_spend_confirmed = Some(entry.txid); @@ -2620,7 +2675,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 +2758,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 { @@ -2790,7 +2848,7 @@ impl ChannelMonitorImpl { self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid: tx.txid(), height, event: OnchainEvent::HTLCSpendConfirmation { - input_idx: input.previous_output.vout, + commitment_tx_output_idx: input.previous_output.vout, preimage: if accepted_preimage_claim || offered_preimage_claim { Some(payment_preimage) } else { None }, // If this is a payment to us (!outbound_htlc, above), @@ -2841,7 +2899,7 @@ impl ChannelMonitorImpl { txid: tx.txid(), height, event: OnchainEvent::HTLCSpendConfirmation { - input_idx: input.previous_output.vout, + commitment_tx_output_idx: input.previous_output.vout, preimage: Some(payment_preimage), on_to_local_output_csv: None, }, @@ -2850,7 +2908,7 @@ impl ChannelMonitorImpl { source, payment_preimage: Some(payment_preimage), payment_hash, - onchain_value_satoshis: Some(amount_msat / 1000), + htlc_value_satoshis: Some(amount_msat / 1000), })); } } else if offered_preimage_claim { @@ -2862,7 +2920,7 @@ impl ChannelMonitorImpl { txid: tx.txid(), height, event: OnchainEvent::HTLCSpendConfirmation { - input_idx: input.previous_output.vout, + commitment_tx_output_idx: input.previous_output.vout, preimage: Some(payment_preimage), on_to_local_output_csv: None, }, @@ -2871,7 +2929,7 @@ impl ChannelMonitorImpl { source, payment_preimage: Some(payment_preimage), payment_hash, - onchain_value_satoshis: Some(amount_msat / 1000), + htlc_value_satoshis: Some(amount_msat / 1000), })); } } else { @@ -2889,8 +2947,8 @@ impl ChannelMonitorImpl { height, event: OnchainEvent::HTLCUpdate { source, payment_hash, - onchain_value_satoshis: Some(amount_msat / 1000), - input_idx: Some(input.previous_output.vout), + htlc_value_satoshis: Some(amount_msat / 1000), + commitment_tx_output_idx: Some(input.previous_output.vout), }, }; log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height {})", log_bytes!(payment_hash.0), entry.confirmation_threshold()); @@ -2974,9 +3032,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) { @@ -3059,7 +3116,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> let funding_redeemscript = Readable::read(reader)?; let channel_value_satoshis = Readable::read(reader)?; - let their_cur_revocation_points = { + let their_cur_per_commitment_points = { let first_idx = ::read(reader)?.0; if first_idx == 0 { None @@ -3248,7 +3305,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> counterparty_commitment_params, funding_redeemscript, channel_value_satoshis, - their_cur_revocation_points, + their_cur_per_commitment_points, on_holder_tx_csv, @@ -3290,15 +3347,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 +3380,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 +3634,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 +3673,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 +3705,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 +3736,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)); } }