X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=b89c58646fbfd960ccf98a5736fc4d300b26db8f;hb=ab0739e3ea5df4552cb77d051b7625349e222229;hp=7904d9bdefa4935a68ab44e04722fe5d5a220dc2;hpb=03537cc346b0ab357cfc80021161c9174d3e270f;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 7904d9bd..b89c5864 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -106,7 +106,9 @@ impl Readable for ChannelMonitorUpdate { let len: u64 = Readable::read(r)?; let mut updates = Vec::with_capacity(cmp::min(len as usize, MAX_ALLOC_SIZE / ::core::mem::size_of::())); for _ in 0..len { - updates.push(Readable::read(r)?); + if let Some(upd) = MaybeReadable::read(r)? { + updates.push(upd); + } } read_tlv_fields!(r, {}); Ok(Self { update_id, updates }) @@ -188,8 +190,8 @@ pub enum MonitorEvent { /// A monitor event containing an HTLCUpdate. HTLCEvent(HTLCUpdate), - /// A monitor event that the Channel's commitment transaction was broadcasted. - CommitmentTxBroadcasted(OutPoint), + /// A monitor event that the Channel's commitment transaction was confirmed. + CommitmentTxConfirmed(OutPoint), } /// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on @@ -230,8 +232,13 @@ pub(crate) const CLTV_CLAIM_BUFFER: u32 = 18; /// with at worst this delay, so we are not only using this value as a mercy for them but also /// us as a safeguard to delay with enough time. pub(crate) const LATENCY_GRACE_PERIOD_BLOCKS: u32 = 3; -/// Number of blocks we wait on seeing a HTLC output being solved before we fail corresponding inbound -/// HTLCs. This prevents us from failing backwards and then getting a reorg resulting in us losing money. +/// Number of blocks we wait on seeing a HTLC output being solved before we fail corresponding +/// inbound HTLCs. This prevents us from failing backwards and then getting a reorg resulting in us +/// losing money. +/// +/// Note that this is a library-wide security assumption. If a reorg deeper than this number of +/// blocks occurs, counterparties may be able to steal funds or claims made by and balances exposed +/// by a [`ChannelMonitor`] may be incorrect. // We also use this delay to be sure we can remove our in-flight claim txn from bump candidates buffer. // It may cause spurious generation of bumped claim txn but that's alright given the outpoint is already // solved by a previous claim tx. What we want to avoid is reorg evicting our claim tx and us not @@ -270,11 +277,15 @@ struct HolderSignedTx { b_htlc_key: PublicKey, delayed_payment_key: PublicKey, per_commitment_point: PublicKey, - feerate_per_kw: u32, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, + to_self_value_sat: u64, + feerate_per_kw: u32, } impl_writeable_tlv_based!(HolderSignedTx, { (0, txid, required), + // Note that this is filled in with data from OnchainTxHandler if it's missing. + // For HolderSignedTx objects serialized with 0.0.100+, this should be filled in. + (1, to_self_value_sat, (default_value, u64::max_value())), (2, revocation_key, required), (4, a_htlc_key, required), (6, b_htlc_key, required), @@ -284,26 +295,18 @@ impl_writeable_tlv_based!(HolderSignedTx, { (14, htlc_outputs, vec_type) }); -/// We use this to track counterparty commitment transactions and htlcs outputs and -/// use it to generate any justice or 2nd-stage preimage/timeout transactions. +/// We use this to track static counterparty commitment transaction data and to generate any +/// justice or 2nd-stage preimage/timeout transactions. #[derive(PartialEq)] -struct CounterpartyCommitmentTransaction { +struct CounterpartyCommitmentParameters { counterparty_delayed_payment_base_key: PublicKey, counterparty_htlc_base_key: PublicKey, on_counterparty_tx_csv: u16, - per_htlc: HashMap> } -impl Writeable for CounterpartyCommitmentTransaction { +impl Writeable for CounterpartyCommitmentParameters { fn write(&self, w: &mut W) -> Result<(), io::Error> { - w.write_all(&byte_utils::be64_to_array(self.per_htlc.len() as u64))?; - for (ref txid, ref htlcs) in self.per_htlc.iter() { - w.write_all(&txid[..])?; - w.write_all(&byte_utils::be64_to_array(htlcs.len() as u64))?; - for &ref htlc in htlcs.iter() { - htlc.write(w)?; - } - } + w.write_all(&byte_utils::be64_to_array(0))?; write_tlv_fields!(w, { (0, self.counterparty_delayed_payment_base_key, required), (2, self.counterparty_htlc_base_key, required), @@ -312,23 +315,20 @@ impl Writeable for CounterpartyCommitmentTransaction { Ok(()) } } -impl Readable for CounterpartyCommitmentTransaction { +impl Readable for CounterpartyCommitmentParameters { fn read(r: &mut R) -> Result { let counterparty_commitment_transaction = { + // Versions prior to 0.0.100 had some per-HTLC state stored here, which is no longer + // used. Read it for compatibility. let per_htlc_len: u64 = Readable::read(r)?; - let mut per_htlc = HashMap::with_capacity(cmp::min(per_htlc_len as usize, MAX_ALLOC_SIZE / 64)); for _ in 0..per_htlc_len { - let txid: Txid = Readable::read(r)?; + let _txid: Txid = Readable::read(r)?; let htlcs_count: u64 = Readable::read(r)?; - let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..htlcs_count { - let htlc = Readable::read(r)?; - htlcs.push(htlc); - } - if let Some(_) = per_htlc.insert(txid, htlcs) { - return Err(DecodeError::InvalidValue); + let _htlc: HTLCOutputInCommitment = Readable::read(r)?; } } + let mut counterparty_delayed_payment_base_key = OptionDeserWrapper(None); let mut counterparty_htlc_base_key = OptionDeserWrapper(None); let mut on_counterparty_tx_csv: u16 = 0; @@ -337,11 +337,10 @@ impl Readable for CounterpartyCommitmentTransaction { (2, counterparty_htlc_base_key, required), (4, on_counterparty_tx_csv, required), }); - CounterpartyCommitmentTransaction { + CounterpartyCommitmentParameters { counterparty_delayed_payment_base_key: counterparty_delayed_payment_base_key.0.unwrap(), counterparty_htlc_base_key: counterparty_htlc_base_key.0.unwrap(), on_counterparty_tx_csv, - per_htlc, } }; Ok(counterparty_commitment_transaction) @@ -362,12 +361,21 @@ struct OnchainEventEntry { impl OnchainEventEntry { fn confirmation_threshold(&self) -> u32 { let mut conf_threshold = self.height + ANTI_REORG_DELAY - 1; - if let OnchainEvent::MaturingOutput { - descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) - } = self.event { - // A CSV'd transaction is confirmable in block (input height) + CSV delay, which means - // it's broadcastable when we see the previous block. - conf_threshold = cmp::max(conf_threshold, self.height + descriptor.to_self_delay as u32 - 1); + match self.event { + OnchainEvent::MaturingOutput { + descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) + } => { + // A CSV'd transaction is confirmable in block (input height) + CSV delay, which means + // it's broadcastable when we see the previous block. + conf_threshold = cmp::max(conf_threshold, self.height + descriptor.to_self_delay as u32 - 1); + }, + OnchainEvent::FundingSpendConfirmation { on_local_output_csv: Some(csv), .. } | + OnchainEvent::HTLCSpendConfirmation { on_to_local_output_csv: Some(csv), .. } => { + // A CSV'd transaction is confirmable in block (input height) + CSV delay, which means + // it's broadcastable when we see the previous block. + conf_threshold = cmp::max(conf_threshold, self.height + csv as u32 - 1); + }, + _ => {}, } conf_threshold } @@ -381,35 +389,98 @@ impl OnchainEventEntry { /// once they mature to enough confirmations (ANTI_REORG_DELAY) #[derive(PartialEq)] enum OnchainEvent { - /// HTLC output getting solved by a timeout, at maturation we pass upstream payment source information to solve - /// 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 + /// An outbound HTLC failing after a transaction is confirmed. Used + /// * when an outbound HTLC output is spent by us after the HTLC timed out + /// * an outbound HTLC which was not present in the commitment transaction which appeared + /// on-chain (either because it was not fully committed to or it was dust). + /// Note that this is *not* used for preimage claims, as those are passed upstream immediately, + /// appearing only as an `HTLCSpendConfirmation`, below. HTLCUpdate { source: HTLCSource, payment_hash: PaymentHash, onchain_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, }, MaturingOutput { descriptor: SpendableOutputDescriptor, }, + /// A spend of the funding output, either a commitment transaction or a cooperative closing + /// transaction. + FundingSpendConfirmation { + /// The CSV delay for the output of the funding spend transaction (implying it is a local + /// commitment transaction, and this is the delay on the to_self output). + on_local_output_csv: Option, + }, + /// A spend of a commitment transaction HTLC output, set in the cases where *no* `HTLCUpdate` + /// is constructed. This is used when + /// * an outbound HTLC is claimed by our counterparty with a preimage, causing us to + /// immediately claim the HTLC on the inbound edge and track the resolution here, + /// * an inbound HTLC is claimed by our counterparty (with a timeout), + /// * an inbound HTLC is claimed by us (with a preimage). + /// * a revoked-state HTLC transaction was broadcasted, which was claimed by the revocation + /// signature. + HTLCSpendConfirmation { + input_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, + /// we set this to the output CSV value which we will have to wait until to spend the + /// output (and generate a SpendableOutput event). + on_to_local_output_csv: Option, + }, } -impl_writeable_tlv_based!(OnchainEventEntry, { - (0, txid, required), - (2, height, required), - (4, event, required), -}); +impl Writeable for OnchainEventEntry { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + write_tlv_fields!(writer, { + (0, self.txid, required), + (2, self.height, required), + (4, self.event, required), + }); + Ok(()) + } +} + +impl MaybeReadable for OnchainEventEntry { + fn read(reader: &mut R) -> Result, DecodeError> { + let mut txid = Default::default(); + let mut height = 0; + let mut event = None; + read_tlv_fields!(reader, { + (0, txid, required), + (2, height, required), + (4, event, ignorable), + }); + if let Some(ev) = event { + Ok(Some(Self { txid, height, event: ev })) + } else { + Ok(None) + } + } +} -impl_writeable_tlv_based_enum!(OnchainEvent, +impl_writeable_tlv_based_enum_upgradable!(OnchainEvent, (0, HTLCUpdate) => { (0, source, required), (1, onchain_value_satoshis, option), (2, payment_hash, required), + (3, input_idx, option), }, (1, MaturingOutput) => { (0, descriptor, required), }, -;); + (3, FundingSpendConfirmation) => { + (0, on_local_output_csv, option), + }, + (5, HTLCSpendConfirmation) => { + (0, input_idx, required), + (2, preimage, option), + (4, on_to_local_output_csv, option), + }, + +); #[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] @@ -438,9 +509,12 @@ pub(crate) enum ChannelMonitorUpdateStep { /// think we've fallen behind! should_broadcast: bool, }, + ShutdownScript { + scriptpubkey: Script, + }, } -impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep, +impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep, (0, LatestHolderCommitmentTXInfo) => { (0, commitment_tx, required), (2, htlc_outputs, vec_type), @@ -461,7 +535,76 @@ impl_writeable_tlv_based_enum!(ChannelMonitorUpdateStep, (4, ChannelForceClosed) => { (0, should_broadcast, required), }, -;); + (5, ShutdownScript) => { + (0, scriptpubkey, required), + }, +); + +/// Details about the balance(s) available for spending once the channel appears on chain. +/// +/// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not +/// be provided. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(test, derive(PartialOrd, Ord))] +pub enum Balance { + /// The channel is not yet closed (or the commitment or closing transaction has not yet + /// appeared in a block). The given balance is claimable (less on-chain fees) if the channel is + /// force-closed now. + ClaimableOnChannelClose { + /// The amount available to claim, in satoshis, excluding the on-chain fees which will be + /// required to do so. + claimable_amount_satoshis: u64, + }, + /// The channel has been closed, and the given balance is ours but awaiting confirmations until + /// we consider it spendable. + ClaimableAwaitingConfirmations { + /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which + /// were spent in broadcasting the transaction. + claimable_amount_satoshis: u64, + /// The height at which an [`Event::SpendableOutputs`] event will be generated for this + /// amount. + confirmation_height: u32, + }, + /// The channel has been closed, and the given balance should be ours but awaiting spending + /// transaction confirmation. If the spending transaction does not confirm in time, it is + /// possible our counterparty can take the funds by broadcasting an HTLC timeout on-chain. + /// + /// Once the spending transaction confirms, before it has reached enough confirmations to be + /// considered safe from chain reorganizations, the balance will instead be provided via + /// [`Balance::ClaimableAwaitingConfirmations`]. + ContentiousClaimable { + /// The amount available to claim, in satoshis, excluding the on-chain fees which will be + /// required to do so. + claimable_amount_satoshis: u64, + /// The height at which the counterparty may be able to claim the balance if we have not + /// done so. + timeout_height: u32, + }, + /// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain + /// fees) if the counterparty does not know the preimage for the HTLCs. These are somewhat + /// likely to be claimed by our counterparty before we do. + MaybeClaimableHTLCAwaitingTimeout { + /// The amount available to claim, in satoshis, excluding the on-chain fees which will be + /// required to do so. + claimable_amount_satoshis: u64, + /// The height at which we will be able to claim the balance if our counterparty has not + /// done so. + claimable_height: u32, + }, +} + +/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY. +#[derive(PartialEq)] +struct IrrevocablyResolvedHTLC { + input_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), + (2, payment_preimage, option), +}); /// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates /// on-chain transactions to ensure no loss of funds occurs. @@ -493,7 +636,7 @@ pub(crate) struct ChannelMonitorImpl { destination_script: Script, broadcasted_holder_revokable_script: Option<(Script, PublicKey, PublicKey)>, counterparty_payment_script: Script, - shutdown_script: Script, + shutdown_script: Option