X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=d69f2baf560cb8809b40dfb1fa4a535e06ba1073;hb=2eb7db9ace08b57bfedbdac2b26961897b032e0b;hp=f789b4a7ee7fc92a4ee547678419ee00071cd075;hpb=79ffc5eac94cb618ff905894d480864384d0764f;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index f789b4a7e..d69f2baf5 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -198,7 +198,12 @@ pub struct HTLCUpdate { pub(crate) payment_preimage: Option, pub(crate) source: HTLCSource } -impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); +impl_writeable_tlv_based!(HTLCUpdate, { + (0, payment_hash), + (2, source), +}, { + (4, payment_preimage) +}, {}); /// 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. @@ -264,6 +269,17 @@ struct HolderSignedTx { feerate_per_kw: u32, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, } +impl_writeable_tlv_based!(HolderSignedTx, { + (0, txid), + (2, revocation_key), + (4, a_htlc_key), + (6, b_htlc_key), + (8, delayed_payment_key), + (10, per_commitment_point), + (12, feerate_per_kw), +}, {}, { + (14, htlc_outputs) +}); /// We use this to track counterparty commitment transactions and htlcs outputs and /// use it to generate any justice or 2nd-stage preimage/timeout transactions. @@ -351,13 +367,30 @@ enum OnchainEvent { /// inbound HTLC in backward channel. Note, in case of preimage, we pass info to upstream without delay as we can /// only win from it, so it's never an OnchainEvent HTLCUpdate { - htlc_update: (HTLCSource, PaymentHash), + source: HTLCSource, + payment_hash: PaymentHash, }, MaturingOutput { descriptor: SpendableOutputDescriptor, }, } +impl_writeable_tlv_based!(OnchainEventEntry, { + (0, txid), + (2, height), + (4, event), +}, {}, {}); + +impl_writeable_tlv_based_enum!(OnchainEvent, + (0, HTLCUpdate) => { + (0, source), + (2, payment_hash), + }, {}, {}, + (1, MaturingOutput) => { + (0, descriptor), + }, {}, {}, +;); + #[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] pub(crate) enum ChannelMonitorUpdateStep { @@ -387,98 +420,30 @@ pub(crate) enum ChannelMonitorUpdateStep { }, } -impl Writeable for ChannelMonitorUpdateStep { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { - match self { - &ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { ref commitment_tx, ref htlc_outputs } => { - 0u8.write(w)?; - commitment_tx.write(w)?; - (htlc_outputs.len() as u64).write(w)?; - for &(ref output, ref signature, ref source) in htlc_outputs.iter() { - output.write(w)?; - signature.write(w)?; - source.write(w)?; - } - } - &ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { commitment_txid, ref htlc_outputs, ref commitment_number, ref their_revocation_point } => { - 1u8.write(w)?; - commitment_txid.write(w)?; - commitment_number.write(w)?; - their_revocation_point.write(w)?; - (htlc_outputs.len() as u64).write(w)?; - for &(ref output, ref source) in htlc_outputs.iter() { - output.write(w)?; - source.as_ref().map(|b| b.as_ref()).write(w)?; - } - }, - &ChannelMonitorUpdateStep::PaymentPreimage { ref payment_preimage } => { - 2u8.write(w)?; - payment_preimage.write(w)?; - }, - &ChannelMonitorUpdateStep::CommitmentSecret { ref idx, ref secret } => { - 3u8.write(w)?; - idx.write(w)?; - secret.write(w)?; - }, - &ChannelMonitorUpdateStep::ChannelForceClosed { ref should_broadcast } => { - 4u8.write(w)?; - should_broadcast.write(w)?; - }, - } - Ok(()) - } -} -impl Readable for ChannelMonitorUpdateStep { - fn read(r: &mut R) -> Result { - match Readable::read(r)? { - 0u8 => { - Ok(ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { - commitment_tx: Readable::read(r)?, - htlc_outputs: { - let len: u64 = Readable::read(r)?; - let mut res = Vec::new(); - for _ in 0..len { - res.push((Readable::read(r)?, Readable::read(r)?, Readable::read(r)?)); - } - res - }, - }) - }, - 1u8 => { - Ok(ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { - commitment_txid: Readable::read(r)?, - commitment_number: Readable::read(r)?, - their_revocation_point: Readable::read(r)?, - htlc_outputs: { - let len: u64 = Readable::read(r)?; - let mut res = Vec::new(); - for _ in 0..len { - res.push((Readable::read(r)?, as Readable>::read(r)?.map(|o| Box::new(o)))); - } - res - }, - }) - }, - 2u8 => { - Ok(ChannelMonitorUpdateStep::PaymentPreimage { - payment_preimage: Readable::read(r)?, - }) - }, - 3u8 => { - Ok(ChannelMonitorUpdateStep::CommitmentSecret { - idx: Readable::read(r)?, - secret: Readable::read(r)?, - }) - }, - 4u8 => { - Ok(ChannelMonitorUpdateStep::ChannelForceClosed { - should_broadcast: Readable::read(r)? - }) - }, - _ => Err(DecodeError::InvalidValue), - } - } -} +impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep, + (0, LatestHolderCommitmentTXInfo) => { + (0, commitment_tx), + }, {}, { + (2, htlc_outputs), + }, + (1, LatestCounterpartyCommitmentTXInfo) => { + (0, commitment_txid), + (2, commitment_number), + (4, their_revocation_point), + }, {}, { + (6, htlc_outputs), + }, + (2, PaymentPreimage) => { + (0, payment_preimage), + }, {}, {}, + (3, CommitmentSecret) => { + (0, idx), + (2, secret), + }, {}, {}, + (4, ChannelForceClosed) => { + (0, should_broadcast), + }, {}, {}, +;); /// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates /// on-chain transactions to ensure no loss of funds occurs. @@ -753,38 +718,14 @@ impl Writeable for ChannelMonitorImpl { writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; } - macro_rules! serialize_holder_tx { - ($holder_tx: expr) => { - $holder_tx.txid.write(writer)?; - writer.write_all(&$holder_tx.revocation_key.serialize())?; - writer.write_all(&$holder_tx.a_htlc_key.serialize())?; - writer.write_all(&$holder_tx.b_htlc_key.serialize())?; - writer.write_all(&$holder_tx.delayed_payment_key.serialize())?; - writer.write_all(&$holder_tx.per_commitment_point.serialize())?; - - writer.write_all(&byte_utils::be32_to_array($holder_tx.feerate_per_kw))?; - writer.write_all(&byte_utils::be64_to_array($holder_tx.htlc_outputs.len() as u64))?; - for &(ref htlc_output, ref sig, ref htlc_source) in $holder_tx.htlc_outputs.iter() { - serialize_htlc_in_commitment!(htlc_output); - if let &Some(ref their_sig) = sig { - 1u8.write(writer)?; - writer.write_all(&their_sig.serialize_compact())?; - } else { - 0u8.write(writer)?; - } - htlc_source.write(writer)?; - } - } - } - if let Some(ref prev_holder_tx) = self.prev_holder_signed_commitment_tx { writer.write_all(&[1; 1])?; - serialize_holder_tx!(prev_holder_tx); + prev_holder_tx.write(writer)?; } else { writer.write_all(&[0; 1])?; } - serialize_holder_tx!(self.current_holder_commitment_tx); + self.current_holder_commitment_tx.write(writer)?; writer.write_all(&byte_utils::be48_to_array(self.current_counterparty_commitment_number))?; writer.write_all(&byte_utils::be48_to_array(self.current_holder_commitment_number))?; @@ -815,19 +756,7 @@ impl Writeable for ChannelMonitorImpl { writer.write_all(&byte_utils::be64_to_array(self.onchain_events_awaiting_threshold_conf.len() as u64))?; for ref entry in self.onchain_events_awaiting_threshold_conf.iter() { - entry.txid.write(writer)?; - writer.write_all(&byte_utils::be32_to_array(entry.height))?; - match entry.event { - OnchainEvent::HTLCUpdate { ref htlc_update } => { - 0u8.write(writer)?; - htlc_update.0.write(writer)?; - htlc_update.1.write(writer)?; - }, - OnchainEvent::MaturingOutput { ref descriptor } => { - 1u8.write(writer)?; - descriptor.write(writer)?; - }, - } + entry.write(writer)?; } (self.outputs_to_watch.len() as u64).write(writer)?; @@ -1609,17 +1538,18 @@ impl ChannelMonitorImpl { self.onchain_events_awaiting_threshold_conf.retain(|ref entry| { if entry.height != height { return true; } match entry.event { - OnchainEvent::HTLCUpdate { ref htlc_update } => { - htlc_update.0 != **source - }, - _ => true, + OnchainEvent::HTLCUpdate { source: ref update_source, .. } => { + *update_source != **source + }, + _ => true, } }); let entry = OnchainEventEntry { txid: *$txid, height, event: OnchainEvent::HTLCUpdate { - htlc_update: ((**source).clone(), htlc.payment_hash.clone()) + source: (**source).clone(), + payment_hash: htlc.payment_hash.clone(), }, }; log_info!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, entry.confirmation_threshold()); @@ -1675,17 +1605,18 @@ impl ChannelMonitorImpl { self.onchain_events_awaiting_threshold_conf.retain(|ref entry| { if entry.height != height { return true; } match entry.event { - OnchainEvent::HTLCUpdate { ref htlc_update } => { - htlc_update.0 != **source - }, - _ => true, + OnchainEvent::HTLCUpdate { source: ref update_source, .. } => { + *update_source != **source + }, + _ => true, } }); self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid: *$txid, height, event: OnchainEvent::HTLCUpdate { - htlc_update: ((**source).clone(), htlc.payment_hash.clone()) + source: (**source).clone(), + payment_hash: htlc.payment_hash.clone(), }, }); } @@ -1829,16 +1760,16 @@ impl ChannelMonitorImpl { self.onchain_events_awaiting_threshold_conf.retain(|ref entry| { if entry.height != height { return true; } match entry.event { - OnchainEvent::HTLCUpdate { ref htlc_update } => { - htlc_update.0 != $source - }, - _ => true, + OnchainEvent::HTLCUpdate { source: ref update_source, .. } => { + *update_source != $source + }, + _ => true, } }); let entry = OnchainEventEntry { txid: commitment_txid, height, - event: OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash) }, + event: OnchainEvent::HTLCUpdate { source: $source, payment_hash: $payment_hash }, }; log_trace!(logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, entry.confirmation_threshold()); self.onchain_events_awaiting_threshold_conf.push(entry); @@ -1899,7 +1830,7 @@ impl ChannelMonitorImpl { self.holder_tx_signed = true; let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript); let txid = commitment_tx.txid(); - let mut res = vec![commitment_tx]; + let mut holder_transactions = vec![commitment_tx]; for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { if let Some(vout) = htlc.0.transaction_output_index { let preimage = if !htlc.0.offered { @@ -1907,24 +1838,32 @@ impl ChannelMonitorImpl { // We can't build an HTLC-Success transaction without the preimage continue; } + } else if htlc.0.cltv_expiry > self.best_block.height() + 1 { + // Don't broadcast HTLC-Timeout transactions immediately as they don't meet the + // current locktime requirements on-chain. We will broadcast them in + // `block_confirmed` when `would_broadcast_at_height` returns true. + // Note that we add + 1 as transactions are broadcastable when they can be + // confirmed in the next block. + 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); + holder_transactions.push(htlc_tx); } } } // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do. // The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation. - return res; + holder_transactions } #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] + /// Note that this includes possibly-locktimed-in-the-future transactions! fn unsafe_get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { log_trace!(logger, "Getting signed copy of latest holder commitment transaction!"); let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript); let txid = commitment_tx.txid(); - let mut res = vec![commitment_tx]; + let mut holder_transactions = vec![commitment_tx]; for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { if let Some(vout) = htlc.0.transaction_output_index { let preimage = if !htlc.0.offered { @@ -1935,11 +1874,11 @@ impl ChannelMonitorImpl { } 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); + holder_transactions.push(htlc_tx); } } } - return res + holder_transactions } pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec @@ -2101,7 +2040,7 @@ impl ChannelMonitorImpl { let unmatured_htlcs: Vec<_> = self.onchain_events_awaiting_threshold_conf .iter() .filter_map(|entry| match &entry.event { - OnchainEvent::HTLCUpdate { htlc_update } => Some(htlc_update.0.clone()), + OnchainEvent::HTLCUpdate { source, .. } => Some(source), OnchainEvent::MaturingOutput { .. } => None, }) .collect(); @@ -2111,28 +2050,28 @@ 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 { htlc_update } => { + OnchainEvent::HTLCUpdate { ref source, payment_hash } => { // Check for duplicate HTLC resolutions. #[cfg(debug_assertions)] { debug_assert!( - unmatured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(), + unmatured_htlcs.iter().find(|&htlc| htlc == &source).is_none(), "An unmature HTLC transaction conflicts with a maturing one; failed to \ call either transaction_unconfirmed for the conflicting transaction \ or block_disconnected for a block containing it."); debug_assert!( - matured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(), + matured_htlcs.iter().find(|&htlc| htlc == source).is_none(), "A matured HTLC transaction conflicts with a maturing one; failed to \ call either transaction_unconfirmed for the conflicting transaction \ or block_disconnected for a block containing it."); - matured_htlcs.push(htlc_update.0.clone()); + matured_htlcs.push(source.clone()); } - log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0)); + log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!(payment_hash.0)); self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate { - payment_hash: htlc_update.1, + payment_hash: payment_hash, payment_preimage: None, - source: htlc_update.0, + source: source.clone(), })); }, OnchainEvent::MaturingOutput { descriptor } => { @@ -2429,16 +2368,16 @@ impl ChannelMonitorImpl { self.onchain_events_awaiting_threshold_conf.retain(|ref entry| { if entry.height != height { return true; } match entry.event { - OnchainEvent::HTLCUpdate { ref htlc_update } => { - htlc_update.0 != source - }, - _ => true, + OnchainEvent::HTLCUpdate { source: ref htlc_source, .. } => { + *htlc_source != source + }, + _ => true, } }); let entry = OnchainEventEntry { txid: tx.txid(), height, - event: OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash) }, + event: OnchainEvent::HTLCUpdate { source: source, payment_hash: payment_hash }, }; 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()); self.onchain_events_awaiting_threshold_conf.push(entry); @@ -2715,46 +2654,14 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> } } - macro_rules! read_holder_tx { - () => { - { - let txid = Readable::read(reader)?; - let revocation_key = Readable::read(reader)?; - let a_htlc_key = Readable::read(reader)?; - let b_htlc_key = Readable::read(reader)?; - let delayed_payment_key = Readable::read(reader)?; - let per_commitment_point = Readable::read(reader)?; - let feerate_per_kw: u32 = Readable::read(reader)?; - - let htlcs_len: u64 = Readable::read(reader)?; - let mut htlcs = Vec::with_capacity(cmp::min(htlcs_len as usize, MAX_ALLOC_SIZE / 128)); - for _ in 0..htlcs_len { - let htlc = read_htlc_in_commitment!(); - let sigs = match ::read(reader)? { - 0 => None, - 1 => Some(Readable::read(reader)?), - _ => return Err(DecodeError::InvalidValue), - }; - htlcs.push((htlc, sigs, Readable::read(reader)?)); - } - - HolderSignedTx { - txid, - revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw, - htlc_outputs: htlcs - } - } - } - } - let prev_holder_signed_commitment_tx = match ::read(reader)? { 0 => None, 1 => { - Some(read_holder_tx!()) + Some(Readable::read(reader)?) }, _ => return Err(DecodeError::InvalidValue), }; - let current_holder_commitment_tx = read_holder_tx!(); + let current_holder_commitment_tx = Readable::read(reader)?; let current_counterparty_commitment_number = ::read(reader)?.0; let current_holder_commitment_number = ::read(reader)?.0; @@ -2793,25 +2700,7 @@ impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> let waiting_threshold_conf_len: u64 = Readable::read(reader)?; let mut onchain_events_awaiting_threshold_conf = Vec::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128)); for _ in 0..waiting_threshold_conf_len { - let txid = Readable::read(reader)?; - let height = Readable::read(reader)?; - let event = match ::read(reader)? { - 0 => { - let htlc_source = Readable::read(reader)?; - let hash = Readable::read(reader)?; - OnchainEvent::HTLCUpdate { - htlc_update: (htlc_source, hash) - } - }, - 1 => { - let descriptor = Readable::read(reader)?; - OnchainEvent::MaturingOutput { - descriptor - } - }, - _ => return Err(DecodeError::InvalidValue), - }; - onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid, height, event }); + onchain_events_awaiting_threshold_conf.push(Readable::read(reader)?); } let outputs_to_watch_len: u64 = Readable::read(reader)?; @@ -2921,7 +2810,7 @@ mod tests { fn test_prune_preimages() { let secp_ctx = Secp256k1::new(); let logger = Arc::new(TestLogger::new()); - let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())}); + let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))}); let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 }); let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());