X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=650191dacdd8b58fee82715842b2825b23ca8aa1;hb=62edee568985e3362bd1609c6089d05428023925;hp=939337d7b42d572d64c7ab5b1a6224479f6c1ce9;hpb=d3231a23919b49085c09c43d0c1b8f8841e3d23c;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 939337d7..681d895f 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -20,9 +20,8 @@ //! 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; @@ -34,31 +33,33 @@ use bitcoin::secp256k1::{Secp256k1,Signature}; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1; +use ln::{PaymentHash, PaymentPreimage}; use ln::msgs::DecodeError; use ln::chan_utils; use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction}; -use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; -use ln::onchaintx::{OnchainTxHandler, InputDescriptors}; +use ln::channelmanager::HTLCSource; use chain; -use chain::WatchedOutput; +use chain::{BestBlock, WatchedOutput}; use chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use chain::transaction::{OutPoint, TransactionData}; use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface}; +use chain::onchaintx::OnchainTxHandler; +use chain::package::{CounterpartyOfferedHTLCOutput, CounterpartyReceivedHTLCOutput, HolderFundingOutput, HolderHTLCOutput, PackageSolvingData, PackageTemplate, RevokedOutput, RevokedHTLCOutput}; use chain::Filter; use util::logger::Logger; -use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48}; +use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48, OptionDeserWrapper}; use util::byte_utils; use util::events::Event; -use std::collections::{HashMap, HashSet, hash_map}; -use std::{cmp, mem}; -use std::io::Error; -use std::ops::Deref; -use std::sync::Mutex; +use prelude::*; +use core::{cmp, mem}; +use io::{self, Error}; +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. -#[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 { @@ -84,108 +85,78 @@ pub struct ChannelMonitorUpdate { /// then we allow the `ChannelManager` to send a `ChannelMonitorUpdate` with this update ID, /// with the update providing said payment preimage. No other update types are allowed after /// force-close. -pub const CLOSED_CHANNEL_UPDATE_ID: u64 = std::u64::MAX; +pub const CLOSED_CHANNEL_UPDATE_ID: u64 = core::u64::MAX; impl Writeable for ChannelMonitorUpdate { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + write_ver_prefix!(w, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); self.update_id.write(w)?; (self.updates.len() as u64).write(w)?; for update_step in self.updates.iter() { update_step.write(w)?; } + write_tlv_fields!(w, {}); Ok(()) } } impl Readable for ChannelMonitorUpdate { - fn read(r: &mut R) -> Result { + fn read(r: &mut R) -> Result { + let _ver = read_ver_prefix!(r, SERIALIZATION_VERSION); let update_id: u64 = Readable::read(r)?; let len: u64 = Readable::read(r)?; - let mut updates = Vec::with_capacity(cmp::min(len as usize, MAX_ALLOC_SIZE / ::std::mem::size_of::())); + 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 }) } } -/// An error enum representing a failure to persist a channel monitor update. -#[derive(Clone, Debug)] -pub enum ChannelMonitorUpdateErr { - /// Used to indicate a temporary failure (eg connection to a watchtower or remote backup of - /// our state failed, but is expected to succeed at some point in the future). - /// - /// Such a failure will "freeze" a channel, preventing us from revoking old states or - /// submitting new commitment transactions to the counterparty. Once the update(s) which failed - /// have been successfully applied, ChannelManager::channel_monitor_updated can be used to - /// restore the channel to an operational state. - /// - /// Note that a given ChannelManager will *never* re-generate a given ChannelMonitorUpdate. If - /// you return a TemporaryFailure you must ensure that it is written to disk safely before - /// writing out the latest ChannelManager state. - /// - /// Even when a channel has been "frozen" updates to the ChannelMonitor can continue to occur - /// (eg if an inbound HTLC which we forwarded was claimed upstream resulting in us attempting - /// to claim it on this channel) and those updates must be applied wherever they can be. At - /// least one such updated ChannelMonitor must be persisted otherwise PermanentFailure should - /// be returned to get things on-chain ASAP using only the in-memory copy. Obviously updates to - /// the channel which would invalidate previous ChannelMonitors are not made when a channel has - /// been "frozen". - /// - /// Note that even if updates made after TemporaryFailure succeed you must still call - /// channel_monitor_updated to ensure you have the latest monitor and re-enable normal channel - /// operation. - /// - /// Note that the update being processed here will not be replayed for you when you call - /// ChannelManager::channel_monitor_updated, so you must store the update itself along - /// with the persisted ChannelMonitor on your own local disk prior to returning a - /// TemporaryFailure. You may, of course, employ a journaling approach, storing only the - /// ChannelMonitorUpdate on disk without updating the monitor itself, replaying the journal at - /// reload-time. - /// - /// For deployments where a copy of ChannelMonitors and other local state are backed up in a - /// remote location (with local copies persisted immediately), it is anticipated that all - /// updates will return TemporaryFailure until the remote copies could be updated. - TemporaryFailure, - /// Used to indicate no further channel monitor updates will be allowed (eg we've moved on to a - /// different watchtower and cannot update with all watchtowers that were previously informed - /// of this channel). - /// - /// At reception of this error, ChannelManager will force-close the channel and return at - /// least a final ChannelMonitorUpdate::ChannelForceClosed which must be delivered to at - /// least one ChannelMonitor copy. Revocation secret MUST NOT be released and offchain channel - /// update must be rejected. - /// - /// This failure may also signal a failure to update the local persisted copy of one of - /// the channel monitor instance. - /// - /// Note that even when you fail a holder commitment transaction update, you must store the - /// update to ensure you can claim from it in case of a duplicate copy of this ChannelMonitor - /// broadcasts it (e.g distributed channel-monitor deployment) - /// - /// In case of distributed watchtowers deployment, the new version must be written to disk, as - /// state may have been stored but rejected due to a block forcing a commitment broadcast. This - /// storage is used to claim outputs of rejected state confirmed onchain by another watchtower, - /// lagging behind on block processing. - PermanentFailure, -} - -/// General Err type for ChannelMonitor actions. Generally, this implies that the data provided is -/// inconsistent with the ChannelMonitor being called. eg for ChannelMonitor::update_monitor this -/// means you tried to update a monitor for a different channel or the ChannelMonitorUpdate was -/// corrupted. -/// Contains a developer-readable error message. -#[derive(Clone, Debug)] -pub struct MonitorUpdateError(pub &'static str); - /// An event to be processed by the ChannelManager. #[derive(Clone, PartialEq)] 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), + + /// Indicates a [`ChannelMonitor`] update has completed. See + /// [`ChannelMonitorUpdateErr::TemporaryFailure`] for more information on how this is used. + /// + /// [`ChannelMonitorUpdateErr::TemporaryFailure`]: super::ChannelMonitorUpdateErr::TemporaryFailure + UpdateCompleted { + /// The funding outpoint of the [`ChannelMonitor`] that was updated + funding_txo: OutPoint, + /// The Update ID from [`ChannelMonitorUpdate::update_id`] which was applied or + /// [`ChannelMonitor::get_latest_update_id`]. + /// + /// Note that this should only be set to a given update's ID if all previous updates for the + /// same [`ChannelMonitor`] have been applied and persisted. + monitor_update_id: u64, + }, + + /// Indicates a [`ChannelMonitor`] update has failed. See + /// [`ChannelMonitorUpdateErr::PermanentFailure`] for more information on how this is used. + /// + /// [`ChannelMonitorUpdateErr::PermanentFailure`]: super::ChannelMonitorUpdateErr::PermanentFailure + UpdateFailed(OutPoint), } +impl_writeable_tlv_based_enum_upgradable!(MonitorEvent, + // Note that UpdateCompleted and UpdateFailed are currently never serialized to disk as they are + // generated only in ChainMonitor + (0, UpdateCompleted) => { + (0, funding_txo, required), + (2, monitor_update_id, required), + }, +; + (2, HTLCEvent), + (4, CommitmentTxConfirmed), + (6, UpdateFailed), +); /// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on /// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the @@ -194,9 +165,15 @@ pub enum MonitorEvent { pub struct HTLCUpdate { pub(crate) payment_hash: PaymentHash, pub(crate) payment_preimage: Option, - pub(crate) source: HTLCSource + pub(crate) source: HTLCSource, + pub(crate) onchain_value_satoshis: Option, } -impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); +impl_writeable_tlv_based!(HTLCUpdate, { + (0, payment_hash, required), + (1, onchain_value_satoshis, option), + (2, source, required), + (4, payment_preimage, option), +}); /// 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. @@ -205,7 +182,7 @@ pub(crate) const CLTV_SHARED_CLAIM_BUFFER: u32 = 12; /// HTLC-Success transaction. /// In other words, this is an upper bound on how many blocks we think it can take us to get a /// transaction confirmed (and we use it in a few more, equivalent, places). -pub(crate) const CLTV_CLAIM_BUFFER: u32 = 6; +pub(crate) const CLTV_CLAIM_BUFFER: u32 = 18; /// Number of blocks by which point we expect our counterparty to have seen new blocks on the /// network and done a full update_fail_htlc/commitment_signed dance (+ we've updated all our /// copies of ChannelMonitors, including watchtowers). We could enforce the contract by failing @@ -219,13 +196,18 @@ pub(crate) const CLTV_CLAIM_BUFFER: u32 = 6; /// 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. -/// We use also this delay to be sure we can remove our in-flight claim txn from bump candidates buffer. -/// It may cause spurrious generation of bumped claim txn but that's allright 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 -/// keeping bumping another claim tx to solve the outpoint. -pub(crate) const ANTI_REORG_DELAY: u32 = 6; +/// 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 +// keep bumping another claim tx to solve the outpoint. +pub const ANTI_REORG_DELAY: u32 = 6; /// Number of blocks before confirmation at which we fail back an un-relayed HTLC or at which we /// refuse to accept a new HTLC. /// @@ -235,8 +217,6 @@ pub(crate) const ANTI_REORG_DELAY: u32 = 6; /// fail this HTLC, /// 2) if we receive an HTLC within this many blocks of its expiry (plus one to avoid a race /// condition with the above), we will fail this HTLC without telling the user we received it, -/// 3) if we are waiting on a connection or a channel state update to send an HTLC to a peer, and -/// that HTLC expires within this many blocks, we will simply fail the HTLC instead. /// /// (1) is all about protecting us - we need enough time to update the channel state before we hit /// CLTV_CLAIM_BUFFER, at which point we'd go on chain to claim the HTLC with the preimage. @@ -244,9 +224,6 @@ pub(crate) const ANTI_REORG_DELAY: u32 = 6; /// (2) is the same, but with an additional buffer to avoid accepting an HTLC which is immediately /// in a race condition between the user connecting a block (which would fail it) and the user /// providing us the preimage (which would claim it). -/// -/// (3) is about our counterparty - we don't want to relay an HTLC to a counterparty when they may -/// end up force-closing the channel on us to claim it. pub(crate) const HTLC_FAIL_BACK_BUFFER: u32 = CLTV_CLAIM_BUFFER + LATENCY_GRACE_PERIOD_BLOCKS; // TODO(devrandom) replace this with HolderCommitmentTransaction @@ -259,231 +236,212 @@ 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, } - -/// We use this to track counterparty commitment transactions and htlcs outputs and -/// use it to generate any justice or 2nd-stage preimage/timeout transactions. +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), + (8, delayed_payment_key, required), + (10, per_commitment_point, required), + (12, feerate_per_kw, required), + (14, htlc_outputs, vec_type) +}); + +/// 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 { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { - self.counterparty_delayed_payment_base_key.write(w)?; - self.counterparty_htlc_base_key.write(w)?; - w.write_all(&byte_utils::be16_to_array(self.on_counterparty_tx_csv))?; - 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)?; - } - } +impl Writeable for CounterpartyCommitmentParameters { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + 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), + (4, self.on_counterparty_tx_csv, required), + }); Ok(()) } } -impl Readable for CounterpartyCommitmentTransaction { - fn read(r: &mut R) -> Result { +impl Readable for CounterpartyCommitmentParameters { + fn read(r: &mut R) -> Result { let counterparty_commitment_transaction = { - let counterparty_delayed_payment_base_key = Readable::read(r)?; - let counterparty_htlc_base_key = Readable::read(r)?; - let on_counterparty_tx_csv: u16 = Readable::read(r)?; + // 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)?; } } - CounterpartyCommitmentTransaction { - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, + + 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; + read_tlv_fields!(r, { + (0, counterparty_delayed_payment_base_key, required), + (2, counterparty_htlc_base_key, required), + (4, on_counterparty_tx_csv, required), + }); + 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) } } -/// When ChannelMonitor discovers an onchain outpoint being a step of a channel and that it needs -/// to generate a tx to push channel state forward, we cache outpoint-solving tx material to build -/// a new bumped one in case of lenghty confirmation delay -#[derive(Clone, PartialEq)] -pub(crate) enum InputMaterial { - Revoked { - per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, - per_commitment_key: SecretKey, - input_descriptor: InputDescriptors, - amount: u64, - htlc: Option, - on_counterparty_tx_csv: u16, - }, - CounterpartyHTLC { - per_commitment_point: PublicKey, - counterparty_delayed_payment_base_key: PublicKey, - counterparty_htlc_base_key: PublicKey, - preimage: Option, - htlc: HTLCOutputInCommitment - }, - HolderHTLC { - preimage: Option, - amount: u64, - }, - Funding { - funding_redeemscript: Script, - } +/// An entry for an [`OnchainEvent`], stating the block height when the event was observed and the +/// transaction causing it. +/// +/// Used to determine when the on-chain event can be considered safe from a chain reorganization. +#[derive(PartialEq)] +struct OnchainEventEntry { + txid: Txid, + height: u32, + event: OnchainEvent, } -impl Writeable for InputMaterial { - fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { - match self { - &InputMaterial::Revoked { ref per_commitment_point, ref counterparty_delayed_payment_base_key, ref counterparty_htlc_base_key, ref per_commitment_key, ref input_descriptor, ref amount, ref htlc, ref on_counterparty_tx_csv} => { - writer.write_all(&[0; 1])?; - per_commitment_point.write(writer)?; - counterparty_delayed_payment_base_key.write(writer)?; - counterparty_htlc_base_key.write(writer)?; - writer.write_all(&per_commitment_key[..])?; - input_descriptor.write(writer)?; - writer.write_all(&byte_utils::be64_to_array(*amount))?; - htlc.write(writer)?; - on_counterparty_tx_csv.write(writer)?; +impl OnchainEventEntry { + fn confirmation_threshold(&self) -> u32 { + let mut conf_threshold = self.height + ANTI_REORG_DELAY - 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); }, - &InputMaterial::CounterpartyHTLC { ref per_commitment_point, ref counterparty_delayed_payment_base_key, ref counterparty_htlc_base_key, ref preimage, ref htlc} => { - writer.write_all(&[1; 1])?; - per_commitment_point.write(writer)?; - counterparty_delayed_payment_base_key.write(writer)?; - counterparty_htlc_base_key.write(writer)?; - preimage.write(writer)?; - htlc.write(writer)?; + 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); }, - &InputMaterial::HolderHTLC { ref preimage, ref amount } => { - writer.write_all(&[2; 1])?; - preimage.write(writer)?; - writer.write_all(&byte_utils::be64_to_array(*amount))?; - }, - &InputMaterial::Funding { ref funding_redeemscript } => { - writer.write_all(&[3; 1])?; - funding_redeemscript.write(writer)?; - } + _ => {}, } - Ok(()) + conf_threshold } -} -impl Readable for InputMaterial { - fn read(reader: &mut R) -> Result { - let input_material = match ::read(reader)? { - 0 => { - let per_commitment_point = Readable::read(reader)?; - let counterparty_delayed_payment_base_key = Readable::read(reader)?; - let counterparty_htlc_base_key = Readable::read(reader)?; - let per_commitment_key = Readable::read(reader)?; - let input_descriptor = Readable::read(reader)?; - let amount = Readable::read(reader)?; - let htlc = Readable::read(reader)?; - let on_counterparty_tx_csv = Readable::read(reader)?; - InputMaterial::Revoked { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - per_commitment_key, - input_descriptor, - amount, - htlc, - on_counterparty_tx_csv - } - }, - 1 => { - let per_commitment_point = Readable::read(reader)?; - let counterparty_delayed_payment_base_key = Readable::read(reader)?; - let counterparty_htlc_base_key = Readable::read(reader)?; - let preimage = Readable::read(reader)?; - let htlc = Readable::read(reader)?; - InputMaterial::CounterpartyHTLC { - per_commitment_point, - counterparty_delayed_payment_base_key, - counterparty_htlc_base_key, - preimage, - htlc - } - }, - 2 => { - let preimage = Readable::read(reader)?; - let amount = Readable::read(reader)?; - InputMaterial::HolderHTLC { - preimage, - amount, - } - }, - 3 => { - InputMaterial::Funding { - funding_redeemscript: Readable::read(reader)?, - } - } - _ => return Err(DecodeError::InvalidValue), - }; - Ok(input_material) + fn has_reached_confirmation_threshold(&self, best_block: &BestBlock) -> bool { + best_block.height() >= self.confirmation_threshold() } } -/// ClaimRequest is a descriptor structure to communicate between detection -/// and reaction module. They are generated by ChannelMonitor while parsing -/// onchain txn leaked from a channel and handed over to OnchainTxHandler which -/// is responsible for opportunistic aggregation, selecting and enforcing -/// bumping logic, building and signing transactions. -pub(crate) struct ClaimRequest { - // Block height before which claiming is exclusive to one party, - // after reaching it, claiming may be contentious. - pub(crate) absolute_timelock: u32, - // Timeout tx must have nLocktime set which means aggregating multiple - // ones must take the higher nLocktime among them to satisfy all of them. - // Sadly it has few pitfalls, a) it takes longuer to get fund back b) CLTV_DELTA - // of a sooner-HTLC could be swallowed by the highest nLocktime of the HTLC set. - // Do simplify we mark them as non-aggregable. - pub(crate) aggregable: bool, - // Basic bitcoin outpoint (txid, vout) - pub(crate) outpoint: BitcoinOutPoint, - // Following outpoint type, set of data needed to generate transaction digest - // and satisfy witness program. - pub(crate) witness_data: InputMaterial -} - /// 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(Clone, PartialEq)] +#[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 { - htlc_update: (HTLCSource, PaymentHash), + 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, + }, } -const SERIALIZATION_VERSION: u8 = 1; -const MIN_SERIALIZATION_VERSION: u8 = 1; +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) + } + } +} -#[cfg_attr(any(test, feature = "fuzztarget", feature = "_test_utils"), derive(PartialEq))] +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, fuzzing, feature = "_test_utils"), derive(PartialEq))] #[derive(Clone)] pub(crate) enum ChannelMonitorUpdateStep { LatestHolderCommitmentTXInfo { @@ -510,101 +468,116 @@ pub(crate) enum ChannelMonitorUpdateStep { /// think we've fallen behind! should_broadcast: bool, }, + ShutdownScript { + scriptpubkey: Script, + }, } -impl Writeable for ChannelMonitorUpdateStep { - fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { +impl ChannelMonitorUpdateStep { + fn variant_name(&self) -> &'static str { 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)?; - }, + ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { .. } => "LatestHolderCommitmentTXInfo", + ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { .. } => "LatestCounterpartyCommitmentTXInfo", + ChannelMonitorUpdateStep::PaymentPreimage { .. } => "PaymentPreimage", + ChannelMonitorUpdateStep::CommitmentSecret { .. } => "CommitmentSecret", + ChannelMonitorUpdateStep::ChannelForceClosed { .. } => "ChannelForceClosed", + ChannelMonitorUpdateStep::ShutdownScript { .. } => "ShutdownScript", } - 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_upgradable!(ChannelMonitorUpdateStep, + (0, LatestHolderCommitmentTXInfo) => { + (0, commitment_tx, required), + (2, htlc_outputs, vec_type), + }, + (1, LatestCounterpartyCommitmentTXInfo) => { + (0, commitment_txid, required), + (2, commitment_number, required), + (4, their_revocation_point, required), + (6, htlc_outputs, vec_type), + }, + (2, PaymentPreimage) => { + (0, payment_preimage, required), + }, + (3, CommitmentSecret) => { + (0, idx, required), + (2, secret, required), + }, + (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. /// @@ -635,7 +608,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