X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=da30f86149b7b918065de56dfa821267c563f721;hb=62236c70d863bf9456e28a3a1ba784b2e4680a88;hp=fb2cbaddf533a9aa56cbc8586ba7f68f997345f7;hpb=5e86bbf97030c69b0118d1bef39554febfb1cbef;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index fb2cbadd..da30f861 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -20,8 +20,9 @@ //! 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::transaction::OutPoint as BitcoinOutPoint; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; @@ -29,8 +30,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}; @@ -40,7 +41,7 @@ use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLC use ln::channelmanager::HTLCSource; use chain; use chain::{BestBlock, WatchedOutput}; -use chain::chaininterface::{BroadcasterInterface, FeeEstimator}; +use chain::chaininterface::{BroadcasterInterface, FeeEstimator, LowerBoundedFeeEstimator}; use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface}; use chain::onchaintx::OnchainTxHandler; @@ -54,11 +55,17 @@ use util::events::Event; use prelude::*; use core::{cmp, mem}; use io::{self, Error}; +use core::convert::TryInto; use core::ops::Deref; use sync::Mutex; -/// An update generated by the underlying Channel itself which contains some new information the -/// ChannelMonitor should be made aware of. +/// An update generated by the underlying channel itself which contains some new information the +/// [`ChannelMonitor`] should be made aware of. +/// +/// Because this represents only a small number of updates to the underlying state, it is generally +/// much smaller than a full [`ChannelMonitor`]. However, for large single commitment transaction +/// updates (e.g. ones during which there are hundreds of HTLCs pending on the commitment +/// transaction), a single update may reach upwards of 1 MiB in serialized size. #[cfg_attr(any(test, fuzzing, feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] #[must_use] @@ -166,11 +173,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), }); @@ -315,6 +322,7 @@ struct OnchainEventEntry { txid: Txid, height: u32, event: OnchainEvent, + transaction: Option, // Added as optional, but always filled in, in LDK 0.0.110 } impl OnchainEventEntry { @@ -344,6 +352,11 @@ impl OnchainEventEntry { } } +/// The (output index, sats value) for the counterparty's output in a commitment transaction. +/// +/// This was added as an `Option` in 0.0.110. +type CommitmentTxCounterpartyOutputInfo = Option<(u32, u64)>; + /// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it /// once they mature to enough confirmations (ANTI_REORG_DELAY) #[derive(PartialEq)] @@ -357,11 +370,13 @@ 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, }, + /// An output waiting on [`ANTI_REORG_DELAY`] confirmations before we hand the user the + /// [`SpendableOutputDescriptor`]. MaturingOutput { descriptor: SpendableOutputDescriptor, }, @@ -371,6 +386,12 @@ enum OnchainEvent { /// 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, + /// If the funding spend transaction was a known remote commitment transaction, we track + /// the output index and amount of the counterparty's `to_self` output here. + /// + /// This allows us to generate a [`Balance::CounterpartyRevokedOutputClaimable`] for the + /// counterparty output. + commitment_tx_to_counterparty_output: CommitmentTxCounterpartyOutputInfo, }, /// A spend of a commitment transaction HTLC output, set in the cases where *no* `HTLCUpdate` /// is constructed. This is used when @@ -380,8 +401,11 @@ enum OnchainEvent { /// * an inbound HTLC is claimed by us (with a preimage). /// * a revoked-state HTLC transaction was broadcasted, which was claimed by the revocation /// signature. + /// * a revoked-state HTLC transaction was broadcasted, which was claimed by an + /// HTLC-Success/HTLC-Failure transaction (and is still claimable with a 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, @@ -395,6 +419,7 @@ impl Writeable for OnchainEventEntry { fn write(&self, writer: &mut W) -> Result<(), io::Error> { write_tlv_fields!(writer, { (0, self.txid, required), + (1, self.transaction, option), (2, self.height, required), (4, self.event, required), }); @@ -404,16 +429,18 @@ impl Writeable for OnchainEventEntry { impl MaybeReadable for OnchainEventEntry { fn read(reader: &mut R) -> Result, DecodeError> { - let mut txid = Default::default(); + let mut txid = Txid::all_zeros(); + let mut transaction = None; let mut height = 0; let mut event = None; read_tlv_fields!(reader, { (0, txid, required), + (1, transaction, option), (2, height, required), (4, event, ignorable), }); if let Some(ev) = event { - Ok(Some(Self { txid, height, event: ev })) + Ok(Some(Self { txid, transaction, height, event: ev })) } else { Ok(None) } @@ -423,18 +450,19 @@ 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), }, (3, FundingSpendConfirmation) => { (0, on_local_output_csv, option), + (1, commitment_tx_to_counterparty_output, 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 +480,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, @@ -494,7 +522,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,28 +583,84 @@ pub enum Balance { /// 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. + MaybeTimeoutClaimableHTLC { + /// The amount potentially 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, }, + /// HTLCs which we received from our counterparty which are claimable with a preimage which we + /// do not currently have. This will only be claimable if we receive the preimage from the node + /// to which we forwarded this HTLC before the timeout. + MaybePreimageClaimableHTLC { + /// The amount potentially 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 our counterparty will be able to claim the balance if we have not + /// yet received the preimage and claimed it ourselves. + expiry_height: u32, + }, + /// The channel has been closed, and our counterparty broadcasted a revoked commitment + /// transaction. + /// + /// Thus, we're able to claim all outputs in the commitment transaction, one of which has the + /// following amount. + CounterpartyRevokedOutputClaimable { + /// The amount, in satoshis, of the output which we can claim. + /// + /// Note that for outputs from HTLC balances this may be excluding some on-chain fees that + /// were already spent. + claimable_amount_satoshis: u64, + }, } /// 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: Option, + /// The txid of the transaction which resolved the HTLC, this may be a commitment (if the HTLC + /// was not present in the confirmed commitment transaction), HTLC-Success, or HTLC-Timeout + /// transaction. + resolving_txid: Option, // Added as optional, but always filled in, in 0.0.110 /// 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), -}); +// In LDK versions prior to 0.0.111 commitment_tx_output_idx was not Option-al and +// IrrevocablyResolvedHTLC objects only existed for non-dust HTLCs. This was a bug, but to maintain +// backwards compatibility we must ensure we always write out a commitment_tx_output_idx field, +// using `u32::max_value()` as a sentinal to indicate the HTLC was dust. +impl Writeable for IrrevocablyResolvedHTLC { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let mapped_commitment_tx_output_idx = self.commitment_tx_output_idx.unwrap_or(u32::max_value()); + write_tlv_fields!(writer, { + (0, mapped_commitment_tx_output_idx, required), + (1, self.resolving_txid, option), + (2, self.payment_preimage, option), + }); + Ok(()) + } +} + +impl Readable for IrrevocablyResolvedHTLC { + fn read(reader: &mut R) -> Result { + let mut mapped_commitment_tx_output_idx = 0; + let mut resolving_txid = None; + let mut payment_preimage = None; + read_tlv_fields!(reader, { + (0, mapped_commitment_tx_output_idx, required), + (1, resolving_txid, option), + (2, payment_preimage, option), + }); + Ok(Self { + commitment_tx_output_idx: if mapped_commitment_tx_output_idx == u32::max_value() { None } else { Some(mapped_commitment_tx_output_idx) }, + resolving_txid, + payment_preimage, + }) + } +} /// A ChannelMonitor handles chain events (blocks connected and disconnected) and generates /// on-chain transactions to ensure no loss of funds occurs. @@ -619,8 +703,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, @@ -655,6 +739,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 @@ -705,7 +793,11 @@ pub(crate) struct ChannelMonitorImpl { // of block connection between ChannelMonitors and the ChannelManager. funding_spend_seen: bool, + /// Set to `Some` of the confirmed transaction spending the funding input of the channel after + /// reaching `ANTI_REORG_DELAY` confirmations. funding_spend_confirmed: Option, + + confirmed_commitment_tx_counterparty_output: CommitmentTxCounterpartyOutputInfo, /// The set of HTLCs which have been either claimed or failed on chain and have reached /// the requisite confirmations on the claim/fail transaction (either ANTI_REORG_DELAY or the /// spending CSV for revocable outputs). @@ -718,6 +810,9 @@ pub(crate) struct ChannelMonitorImpl { // the full block_connected). best_block: BestBlock, + /// The node_id of our counterparty + counterparty_node_id: Option, + secp_ctx: Secp256k1, //TODO: dedup this a bit... } @@ -753,7 +848,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 || @@ -772,6 +867,7 @@ impl PartialEq for ChannelMonitorImpl { self.holder_tx_signed != other.holder_tx_signed || self.funding_spend_seen != other.funding_spend_seen || self.funding_spend_confirmed != other.funding_spend_confirmed || + self.confirmed_commitment_tx_counterparty_output != other.confirmed_commitment_tx_counterparty_output || self.htlcs_resolved_on_chain != other.htlcs_resolved_on_chain { false @@ -828,7 +924,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())?; @@ -865,6 +961,9 @@ impl Writeable for ChannelMonitorImpl { writer.write_all(&txid[..])?; writer.write_all(&byte_utils::be64_to_array(htlc_infos.len() as u64))?; for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() { + debug_assert!(htlc_source.is_none() || Some(**txid) == self.current_counterparty_commitment_txid + || Some(**txid) == self.prev_counterparty_commitment_txid, + "HTLC Sources for all revoked commitment transactions should be none!"); serialize_htlc_in_commitment!(htlc_output); htlc_source.as_ref().map(|b| b.as_ref()).write(writer)?; } @@ -947,6 +1046,8 @@ impl Writeable for ChannelMonitorImpl { (3, self.htlcs_resolved_on_chain, vec_type), (5, self.pending_monitor_events, vec_type), (7, self.funding_spend_seen, required), + (9, self.counterparty_node_id, option), + (11, self.confirmed_commitment_tx_counterparty_output, option), }); Ok(()) @@ -954,13 +1055,20 @@ impl Writeable for ChannelMonitorImpl { } impl ChannelMonitor { + /// For lockorder enforcement purposes, we need to have a single site which constructs the + /// `inner` mutex, otherwise cases where we lock two monitors at the same time (eg in our + /// PartialEq implementation) we may decide a lockorder violation has occurred. + fn from_impl(imp: ChannelMonitorImpl) -> Self { + ChannelMonitor { inner: Mutex::new(imp) } + } + pub(crate) fn new(secp_ctx: Secp256k1, keys: Signer, shutdown_script: Option