X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=sidebyside;f=lightning%2Fsrc%2Fln%2Fchannelmonitor.rs;h=b601f741ed978a2d3827adf7b9c4b804409e7428;hb=367834ca9039eb64d6f85b6bd4432c735e776b81;hp=cba28982d4872dc39aca0c7025c816d88209adab;hpb=851ab92ea28f4d4c4c67383c9f935d0555d2efd9;p=rust-lightning diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index cba28982..b601f741 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -1,15 +1,26 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + //! The logic to monitor for on-chain transactions and create the relevant claim responses lives //! here. //! //! ChannelMonitor objects are generated by ChannelManager in response to relevant //! messages/actions, and MUST be persisted to disk (and, preferably, remotely) before progress can -//! be made in responding to certain messages, see ManyChannelMonitor for more. +//! be made in responding to certain messages, see [`chain::Watch`] for more. //! //! Note that ChannelMonitors are an important part of the lightning trust model and a copy of the //! latest ChannelMonitor must always be actively monitoring for chain updates (and no out-of-date //! ChannelMonitors should do so). Thus, if you're building rust-lightning into an HSM or other //! security-domain-separated system design, you should consider having multiple paths for //! ChannelMonitors to get out of the HSM and onto monitoring devices. +//! +//! [`chain::Watch`]: ../../chain/trait.Watch.html use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::transaction::{TxOut,Transaction}; @@ -17,33 +28,34 @@ use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::consensus::encode; -use bitcoin::util::hash::BitcoinHash; -use bitcoin_hashes::Hash; -use bitcoin_hashes::sha256::Hash as Sha256; -use bitcoin_hashes::hash160::Hash as Hash160; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin::hashes::Hash; +use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; -use secp256k1::{Secp256k1,Signature}; -use secp256k1::key::{SecretKey,PublicKey}; -use secp256k1; +use bitcoin::secp256k1::{Secp256k1,Signature}; +use bitcoin::secp256k1::key::{SecretKey,PublicKey}; +use bitcoin::secp256k1; use ln::msgs::DecodeError; use ln::chan_utils; -use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, LocalCommitmentTransaction, HTLCType}; +use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HolderCommitmentTransaction, HTLCType}; use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; -use ln::onchaintx::OnchainTxHandler; -use chain::chaininterface::{ChainListener, ChainWatchInterface, BroadcasterInterface, FeeEstimator}; +use ln::onchaintx::{OnchainTxHandler, InputDescriptors}; +use chain; +use chain::chaininterface::{ChainListener, ChainWatchedUtil, BroadcasterInterface, FeeEstimator}; use chain::transaction::OutPoint; use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys}; use util::logger::Logger; -use util::ser::{ReadableArgs, Readable, MaybeReadable, Writer, Writeable, U48}; +use util::ser::{Readable, MaybeReadable, Writer, Writeable, U48}; use util::{byte_utils, events}; +use util::events::Event; -use std::collections::{HashMap, hash_map}; -use std::sync::{Arc,Mutex}; -use std::{hash,cmp, mem}; +use std::collections::{HashMap, HashSet, hash_map}; +use std::sync::Mutex; +use std::{cmp, mem}; use std::ops::Deref; +use std::io::Error; /// An update generated by the underlying Channel itself which contains some new information the /// ChannelMonitor should be made aware of. @@ -91,7 +103,7 @@ pub enum ChannelMonitorUpdateErr { /// 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 remote party. Once the update(s) which failed + /// 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. /// @@ -124,11 +136,24 @@ pub enum ChannelMonitorUpdateErr { 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). This will force-close the channel in question (which will generate one - /// final ChannelMonitorUpdate which must be delivered to at least one ChannelMonitor copy). + /// 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. /// - /// Should also be used to indicate a failure to update the local persisted copy of the channel - /// monitor. + /// 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, } @@ -140,8 +165,21 @@ pub enum ChannelMonitorUpdateErr { #[derive(Debug)] pub struct MonitorUpdateError(pub &'static str); -/// Simple structure send back by ManyChannelMonitor in case of HTLC detected onchain from a -/// forward channel and from which info are needed to update HTLC in a backward channel. +/// An event to be processed by the ChannelManager. +#[derive(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), +} + +/// 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 +/// preimage claim backward will lead to loss of funds. +/// +/// [`chain::Watch`]: ../../chain/trait.Watch.html #[derive(Clone, PartialEq)] pub struct HTLCUpdate { pub(super) payment_hash: PaymentHash, @@ -150,106 +188,104 @@ pub struct HTLCUpdate { } impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); -/// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between -/// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing -/// events to it, while also taking any add/update_monitor events and passing them to some remote -/// server(s). -/// -/// In general, you must always have at least one local copy in memory, which must never fail to -/// update (as it is responsible for broadcasting the latest state in case the channel is closed), -/// and then persist it to various on-disk locations. If, for some reason, the in-memory copy fails -/// to update (eg out-of-memory or some other condition), you must immediately shut down without -/// taking any further action such as writing the current state to disk. This should likely be -/// accomplished via panic!() or abort(). +/// An implementation of a [`chain::Watch`] and ChainListener. /// -/// Note that any updates to a channel's monitor *must* be applied to each instance of the -/// channel's monitor everywhere (including remote watchtowers) *before* this function returns. If -/// an update occurs and a remote watchtower is left with old state, it may broadcast transactions -/// which we have revoked, allowing our counterparty to claim all funds in the channel! +/// May be used in conjunction with [`ChannelManager`] to monitor channels locally or used +/// independently to monitor channels remotely. /// -/// User needs to notify implementors of ManyChannelMonitor when a new block is connected or -/// disconnected using their `block_connected` and `block_disconnected` methods. However, rather -/// than calling these methods directly, the user should register implementors as listeners to the -/// BlockNotifier and call the BlockNotifier's `block_(dis)connected` methods, which will notify -/// all registered listeners in one go. -pub trait ManyChannelMonitor: Send + Sync { - /// Adds a monitor for the given `funding_txo`. - /// - /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with - /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected - /// callbacks with the funding transaction, or any spends of it. - /// - /// Further, the implementer must also ensure that each output returned in - /// monitor.get_outputs_to_watch() is registered to ensure that the provided monitor learns about - /// any spends of any of the outputs. - /// - /// Any spends of outputs which should have been registered which aren't passed to - /// ChannelMonitors via block_connected may result in FUNDS LOSS. - fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; - - /// Updates a monitor for the given `funding_txo`. - /// - /// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with - /// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected - /// callbacks with the funding transaction, or any spends of it. - /// - /// Further, the implementer must also ensure that each output returned in - /// monitor.get_watch_outputs() is registered to ensure that the provided monitor learns about - /// any spends of any of the outputs. - /// - /// Any spends of outputs which should have been registered which aren't passed to - /// ChannelMonitors via block_connected may result in FUNDS LOSS. - fn update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr>; - - /// Used by ChannelManager to get list of HTLC resolved onchain and which needed to be updated - /// with success or failure. - /// - /// You should probably just call through to - /// ChannelMonitor::get_and_clear_pending_htlcs_updated() for each ChannelMonitor and return - /// the full list. - fn get_and_clear_pending_htlcs_updated(&self) -> Vec; -} - -/// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a -/// watchtower or watch our own channels. -/// -/// Note that you must provide your own key by which to refer to channels. -/// -/// If you're accepting remote monitors (ie are implementing a watchtower), you must verify that -/// users cannot overwrite a given channel by providing a duplicate key. ie you should probably -/// index by a PublicKey which is required to sign any updates. -/// -/// If you're using this for local monitoring of your own channels, you probably want to use -/// `OutPoint` as the key, which will give you a ManyChannelMonitor implementation. -pub struct SimpleManyChannelMonitor +/// [`chain::Watch`]: ../../chain/trait.Watch.html +/// [`ChannelManager`]: ../channelmanager/struct.ChannelManager.html +pub struct ChainMonitor where T::Target: BroadcasterInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { - #[cfg(test)] // Used in ChannelManager tests to manipulate channels directly - pub monitors: Mutex>>, - #[cfg(not(test))] - monitors: Mutex>>, - chain_monitor: Arc, + /// The monitors + pub monitors: Mutex>>, + watch_events: Mutex, broadcaster: T, - logger: Arc, + logger: L, fee_estimator: F } -impl<'a, Key : Send + cmp::Eq + hash::Hash, ChanSigner: ChannelKeys, T: Deref + Sync + Send, F: Deref + Sync + Send> - ChainListener for SimpleManyChannelMonitor +struct WatchEventQueue { + watched: ChainWatchedUtil, + events: Vec, +} + +impl WatchEventQueue { + fn new() -> Self { + Self { + watched: ChainWatchedUtil::new(), + events: Vec::new(), + } + } + + fn watch_tx(&mut self, txid: &Txid, script_pubkey: &Script) { + if self.watched.register_tx(txid, script_pubkey) { + self.events.push(chain::WatchEvent::WatchTransaction { + txid: *txid, + script_pubkey: script_pubkey.clone() + }); + } + } + + fn watch_output(&mut self, outpoint: (&Txid, usize), script_pubkey: &Script) { + let (txid, index) = outpoint; + if self.watched.register_outpoint((*txid, index as u32), script_pubkey) { + self.events.push(chain::WatchEvent::WatchOutput { + outpoint: OutPoint { + txid: *txid, + index: index as u16, + }, + script_pubkey: script_pubkey.clone(), + }); + } + } + + fn dequeue_events(&mut self) -> Vec { + let mut pending_events = Vec::with_capacity(self.events.len()); + pending_events.append(&mut self.events); + pending_events + } + + fn filter_block<'a>(&self, txdata: &[(usize, &'a Transaction)]) -> Vec<(usize, &'a Transaction)> { + let mut matched_txids = HashSet::new(); + txdata.iter().filter(|&&(_, tx)| { + // A tx matches the filter if it either matches the filter directly (via does_match_tx) + // or if it is a descendant of another matched transaction within the same block. + let mut matched = self.watched.does_match_tx(tx); + for input in tx.input.iter() { + if matched || matched_txids.contains(&input.previous_output.txid) { + matched = true; + break; + } + } + if matched { + matched_txids.insert(tx.txid()); + } + matched + }).map(|e| *e).collect() + } +} + +impl + ChainListener for ChainMonitor where T::Target: BroadcasterInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { - fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) { - let block_hash = header.bitcoin_hash(); + fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) { + let mut watch_events = self.watch_events.lock().unwrap(); + let matched_txn = watch_events.filter_block(txdata); { let mut monitors = self.monitors.lock().unwrap(); for monitor in monitors.values_mut() { - let txn_outputs = monitor.block_connected(txn_matched, height, &block_hash, &*self.broadcaster, &*self.fee_estimator); + let txn_outputs = monitor.block_connected(header, &matched_txn, height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); for (ref txid, ref outputs) in txn_outputs { for (idx, output) in outputs.iter().enumerate() { - self.chain_monitor.install_watch_outpoint((txid.clone(), idx as u32), &output.script_pubkey); + watch_events.watch_output((txid, idx), &output.script_pubkey); } } } @@ -257,103 +293,102 @@ impl<'a, Key : Send + cmp::Eq + hash::Hash, ChanSigner: ChannelKeys, T: Deref + } fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) { - let block_hash = header.bitcoin_hash(); let mut monitors = self.monitors.lock().unwrap(); for monitor in monitors.values_mut() { - monitor.block_disconnected(disconnected_height, &block_hash, &*self.broadcaster, &*self.fee_estimator); + monitor.block_disconnected(header, disconnected_height, &*self.broadcaster, &*self.fee_estimator, &*self.logger); } } } -impl SimpleManyChannelMonitor +impl ChainMonitor where T::Target: BroadcasterInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { /// Creates a new object which can be used to monitor several channels given the chain /// interface with which to register to receive notifications. - pub fn new(chain_monitor: Arc, broadcaster: T, logger: Arc, feeest: F) -> SimpleManyChannelMonitor { - let res = SimpleManyChannelMonitor { + pub fn new(broadcaster: T, logger: L, feeest: F) -> Self { + Self { monitors: Mutex::new(HashMap::new()), - chain_monitor, + watch_events: Mutex::new(WatchEventQueue::new()), broadcaster, logger, fee_estimator: feeest, - }; - - res + } } - /// Adds or updates the monitor which monitors the channel referred to by the given key. - pub fn add_monitor_by_key(&self, key: Key, monitor: ChannelMonitor) -> Result<(), MonitorUpdateError> { + /// Adds the monitor that watches the channel referred to by the given outpoint. + fn add_monitor(&self, outpoint: OutPoint, monitor: ChannelMonitor) -> Result<(), MonitorUpdateError> { + let mut watch_events = self.watch_events.lock().unwrap(); let mut monitors = self.monitors.lock().unwrap(); - let entry = match monitors.entry(key) { - hash_map::Entry::Occupied(_) => return Err(MonitorUpdateError("Channel monitor for given key is already present")), + let entry = match monitors.entry(outpoint) { + hash_map::Entry::Occupied(_) => return Err(MonitorUpdateError("Channel monitor for given outpoint is already present")), hash_map::Entry::Vacant(e) => e, }; - match monitor.onchain_detection.funding_info { - None => { - return Err(MonitorUpdateError("Try to update a useless monitor without funding_txo !")); - }, - Some((ref outpoint, ref script)) => { - log_trace!(self, "Got new Channel Monitor for channel {}", log_bytes!(outpoint.to_channel_id()[..])); - self.chain_monitor.install_watch_tx(&outpoint.txid, script); - self.chain_monitor.install_watch_outpoint((outpoint.txid, outpoint.index as u32), script); - }, - } - for (txid, outputs) in monitor.get_outputs_to_watch().iter() { - for (idx, script) in outputs.iter().enumerate() { - self.chain_monitor.install_watch_outpoint((*txid, idx as u32), script); + { + let funding_txo = monitor.get_funding_txo(); + log_trace!(self.logger, "Got new Channel Monitor for channel {}", log_bytes!(funding_txo.0.to_channel_id()[..])); + watch_events.watch_tx(&funding_txo.0.txid, &funding_txo.1); + watch_events.watch_output((&funding_txo.0.txid, funding_txo.0.index as usize), &funding_txo.1); + for (txid, outputs) in monitor.get_outputs_to_watch().iter() { + for (idx, script) in outputs.iter().enumerate() { + watch_events.watch_output((txid, idx), script); + } } } entry.insert(monitor); Ok(()) } - /// Updates the monitor which monitors the channel referred to by the given key. - pub fn update_monitor_by_key(&self, key: Key, update: ChannelMonitorUpdate) -> Result<(), MonitorUpdateError> { + /// Updates the monitor that watches the channel referred to by the given outpoint. + fn update_monitor(&self, outpoint: OutPoint, update: ChannelMonitorUpdate) -> Result<(), MonitorUpdateError> { let mut monitors = self.monitors.lock().unwrap(); - match monitors.get_mut(&key) { + match monitors.get_mut(&outpoint) { Some(orig_monitor) => { - log_trace!(self, "Updating Channel Monitor for channel {}", log_funding_info!(orig_monitor.onchain_detection)); - orig_monitor.update_monitor(update, &self.broadcaster) + log_trace!(self.logger, "Updating Channel Monitor for channel {}", log_funding_info!(orig_monitor)); + orig_monitor.update_monitor(update, &self.broadcaster, &self.logger) }, None => Err(MonitorUpdateError("No such monitor registered")) } } } -impl ManyChannelMonitor for SimpleManyChannelMonitor +impl chain::Watch for ChainMonitor where T::Target: BroadcasterInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { - fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { - match self.add_monitor_by_key(funding_txo, monitor) { + type Keys = ChanSigner; + + fn watch_channel(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { + match self.add_monitor(funding_txo, monitor) { Ok(_) => Ok(()), Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), } } - fn update_monitor(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr> { - match self.update_monitor_by_key(funding_txo, update) { + fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr> { + match self.update_monitor(funding_txo, update) { Ok(_) => Ok(()), Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), } } - fn get_and_clear_pending_htlcs_updated(&self) -> Vec { - let mut pending_htlcs_updated = Vec::new(); + fn release_pending_monitor_events(&self) -> Vec { + let mut pending_monitor_events = Vec::new(); for chan in self.monitors.lock().unwrap().values_mut() { - pending_htlcs_updated.append(&mut chan.get_and_clear_pending_htlcs_updated()); + pending_monitor_events.append(&mut chan.get_and_clear_pending_monitor_events()); } - pending_htlcs_updated + pending_monitor_events } } -impl events::EventsProvider for SimpleManyChannelMonitor +impl events::EventsProvider for ChainMonitor where T::Target: BroadcasterInterface, - F::Target: FeeEstimator + F::Target: FeeEstimator, + L::Target: Logger, { - fn get_and_clear_pending_events(&self) -> Vec { + fn get_and_clear_pending_events(&self) -> Vec { let mut pending_events = Vec::new(); for chan in self.monitors.lock().unwrap().values_mut() { pending_events.append(&mut chan.get_and_clear_pending_events()); @@ -362,6 +397,16 @@ impl chain::WatchEventProvider for ChainMonitor + where T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn release_pending_watch_events(&self) -> Vec { + self.watch_events.lock().unwrap().dequeue_events() + } +} + /// 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. pub(crate) const CLTV_SHARED_CLAIM_BUFFER: u32 = 12; @@ -390,89 +435,160 @@ pub(crate) const LATENCY_GRACE_PERIOD_BLOCKS: u32 = 3; /// 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; - -struct OnchainDetection { - keys: ChanSigner, - funding_info: Option<(OutPoint, Script)>, - current_remote_commitment_txid: Option, - prev_remote_commitment_txid: Option, -} - -#[cfg(any(test, feature = "fuzztarget"))] -impl PartialEq for OnchainDetection { - fn eq(&self, other: &Self) -> bool { - self.keys.pubkeys() == other.keys.pubkeys() - } -} +/// Number of blocks before confirmation at which we fail back an un-relayed HTLC or at which we +/// refuse to accept a new HTLC. +/// +/// This is used for a few separate purposes: +/// 1) if we've received an MPP HTLC to us and it expires within this many blocks and we are +/// waiting on additional parts (or waiting on the preimage for any HTLC from the user), we will +/// 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. +/// +/// (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; #[derive(Clone, PartialEq)] -struct LocalSignedTx { +struct HolderSignedTx { /// txid of the transaction in tx, just used to make comparison faster - txid: Sha256dHash, + txid: Txid, revocation_key: PublicKey, a_htlc_key: PublicKey, b_htlc_key: PublicKey, delayed_payment_key: PublicKey, per_commitment_point: PublicKey, - feerate_per_kw: u64, + feerate_per_kw: u32, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, } +/// We use this to track counterparty commitment transactions and htlcs outputs and +/// use it to generate any justice or 2nd-stage preimage/timeout transactions. +#[derive(PartialEq)] +struct CounterpartyCommitmentTransaction { + 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)?; + } + } + Ok(()) + } +} +impl Readable for CounterpartyCommitmentTransaction { + 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)?; + 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 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); + } + } + CounterpartyCommitmentTransaction { + counterparty_delayed_payment_base_key, + counterparty_htlc_base_key, + 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 { - witness_script: Script, - pubkey: Option, - key: SecretKey, - is_htlc: bool, + 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, }, - RemoteHTLC { - witness_script: Script, - key: SecretKey, + CounterpartyHTLC { + per_commitment_point: PublicKey, + counterparty_delayed_payment_base_key: PublicKey, + counterparty_htlc_base_key: PublicKey, preimage: Option, - amount: u64, - locktime: u32, + htlc: HTLCOutputInCommitment }, - LocalHTLC { + HolderHTLC { preimage: Option, amount: u64, }, Funding { - channel_value: u64, + funding_redeemscript: Script, } } impl Writeable for InputMaterial { fn write(&self, writer: &mut W) -> Result<(), ::std::io::Error> { match self { - &InputMaterial::Revoked { ref witness_script, ref pubkey, ref key, ref is_htlc, ref amount} => { + &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])?; - witness_script.write(writer)?; - pubkey.write(writer)?; - writer.write_all(&key[..])?; - is_htlc.write(writer)?; + 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)?; }, - &InputMaterial::RemoteHTLC { ref witness_script, ref key, ref preimage, ref amount, ref locktime } => { + &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])?; - witness_script.write(writer)?; - key.write(writer)?; + per_commitment_point.write(writer)?; + counterparty_delayed_payment_base_key.write(writer)?; + counterparty_htlc_base_key.write(writer)?; preimage.write(writer)?; - writer.write_all(&byte_utils::be64_to_array(*amount))?; - writer.write_all(&byte_utils::be32_to_array(*locktime))?; + htlc.write(writer)?; }, - &InputMaterial::LocalHTLC { ref preimage, ref amount } => { + &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 channel_value } => { + &InputMaterial::Funding { ref funding_redeemscript } => { writer.write_all(&[3; 1])?; - channel_value.write(writer)?; + funding_redeemscript.write(writer)?; } } Ok(()) @@ -483,45 +599,50 @@ impl Readable for InputMaterial { fn read(reader: &mut R) -> Result { let input_material = match ::read(reader)? { 0 => { - let witness_script = Readable::read(reader)?; - let pubkey = Readable::read(reader)?; - let key = Readable::read(reader)?; - let is_htlc = Readable::read(reader)?; + 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 { - witness_script, - pubkey, - key, - is_htlc, - amount + 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 witness_script = Readable::read(reader)?; - let key = Readable::read(reader)?; + 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 amount = Readable::read(reader)?; - let locktime = Readable::read(reader)?; - InputMaterial::RemoteHTLC { - witness_script, - key, + let htlc = Readable::read(reader)?; + InputMaterial::CounterpartyHTLC { + per_commitment_point, + counterparty_delayed_payment_base_key, + counterparty_htlc_base_key, preimage, - amount, - locktime + htlc } }, 2 => { let preimage = Readable::read(reader)?; let amount = Readable::read(reader)?; - InputMaterial::LocalHTLC { + InputMaterial::HolderHTLC { preimage, amount, } }, 3 => { - let channel_value = Readable::read(reader)?; InputMaterial::Funding { - channel_value + funding_redeemscript: Readable::read(reader)?, } } _ => return Err(DecodeError::InvalidValue), @@ -573,16 +694,11 @@ const MIN_SERIALIZATION_VERSION: u8 = 1; #[cfg_attr(test, derive(PartialEq))] #[derive(Clone)] pub(super) enum ChannelMonitorUpdateStep { - LatestLocalCommitmentTXInfo { - // TODO: We really need to not be generating a fully-signed transaction in Channel and - // passing it here, we need to hold off so that the ChanSigner can enforce a - // only-sign-local-state-for-broadcast once invariant: - commitment_tx: LocalCommitmentTransaction, - local_keys: chan_utils::TxCreationKeys, - feerate_per_kw: u64, + LatestHolderCommitmentTXInfo { + commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, }, - LatestRemoteCommitmentTXInfo { + LatestCounterpartyCommitmentTXInfo { unsigned_commitment_tx: Transaction, // TODO: We should actually only need the txid here htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, @@ -595,15 +711,10 @@ pub(super) enum ChannelMonitorUpdateStep { idx: u64, secret: [u8; 32], }, - /// Indicates our channel is likely a stale version, we're closing, but this update should - /// allow us to spend what is ours if our counterparty broadcasts their latest state. - RescueRemoteCommitmentTXInfo { - their_current_per_commitment_point: PublicKey, - }, - /// Used to indicate that the no future updates will occur, and likely that the latest local + /// Used to indicate that the no future updates will occur, and likely that the latest holder /// commitment transaction(s) should be broadcast, as the channel has been force-closed. ChannelForceClosed { - /// If set to false, we shouldn't broadcast the latest local commitment transaction as we + /// If set to false, we shouldn't broadcast the latest holder commitment transaction as we /// think we've fallen behind! should_broadcast: bool, }, @@ -612,11 +723,9 @@ pub(super) enum ChannelMonitorUpdateStep { impl Writeable for ChannelMonitorUpdateStep { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { match self { - &ChannelMonitorUpdateStep::LatestLocalCommitmentTXInfo { ref commitment_tx, ref local_keys, ref feerate_per_kw, ref htlc_outputs } => { + &ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { ref commitment_tx, ref htlc_outputs } => { 0u8.write(w)?; commitment_tx.write(w)?; - local_keys.write(w)?; - feerate_per_kw.write(w)?; (htlc_outputs.len() as u64).write(w)?; for &(ref output, ref signature, ref source) in htlc_outputs.iter() { output.write(w)?; @@ -624,7 +733,7 @@ impl Writeable for ChannelMonitorUpdateStep { source.write(w)?; } } - &ChannelMonitorUpdateStep::LatestRemoteCommitmentTXInfo { ref unsigned_commitment_tx, ref htlc_outputs, ref commitment_number, ref their_revocation_point } => { + &ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { ref unsigned_commitment_tx, ref htlc_outputs, ref commitment_number, ref their_revocation_point } => { 1u8.write(w)?; unsigned_commitment_tx.write(w)?; commitment_number.write(w)?; @@ -644,12 +753,8 @@ impl Writeable for ChannelMonitorUpdateStep { idx.write(w)?; secret.write(w)?; }, - &ChannelMonitorUpdateStep::RescueRemoteCommitmentTXInfo { ref their_current_per_commitment_point } => { - 4u8.write(w)?; - their_current_per_commitment_point.write(w)?; - }, &ChannelMonitorUpdateStep::ChannelForceClosed { ref should_broadcast } => { - 5u8.write(w)?; + 4u8.write(w)?; should_broadcast.write(w)?; }, } @@ -660,10 +765,8 @@ impl Readable for ChannelMonitorUpdateStep { fn read(r: &mut R) -> Result { match Readable::read(r)? { 0u8 => { - Ok(ChannelMonitorUpdateStep::LatestLocalCommitmentTXInfo { + Ok(ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx: Readable::read(r)?, - local_keys: Readable::read(r)?, - feerate_per_kw: Readable::read(r)?, htlc_outputs: { let len: u64 = Readable::read(r)?; let mut res = Vec::new(); @@ -675,7 +778,7 @@ impl Readable for ChannelMonitorUpdateStep { }) }, 1u8 => { - Ok(ChannelMonitorUpdateStep::LatestRemoteCommitmentTXInfo { + Ok(ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { unsigned_commitment_tx: Readable::read(r)?, commitment_number: Readable::read(r)?, their_revocation_point: Readable::read(r)?, @@ -701,11 +804,6 @@ impl Readable for ChannelMonitorUpdateStep { }) }, 4u8 => { - Ok(ChannelMonitorUpdateStep::RescueRemoteCommitmentTXInfo { - their_current_per_commitment_point: Readable::read(r)?, - }) - }, - 5u8 => { Ok(ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: Readable::read(r)? }) @@ -722,7 +820,7 @@ impl Readable for ChannelMonitorUpdateStep { /// information and are actively monitoring the chain. /// /// Pending Events or updated HTLCs which have not yet been read out by -/// get_and_clear_pending_htlcs_updated or get_and_clear_pending_events are serialized to disk and +/// get_and_clear_pending_monitor_events or get_and_clear_pending_events are serialized to disk and /// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events /// gotten are fully handled before re-serializing the new state. pub struct ChannelMonitor { @@ -730,53 +828,55 @@ pub struct ChannelMonitor { commitment_transaction_number_obscure_factor: u64, destination_script: Script, - broadcasted_local_revokable_script: Option<(Script, SecretKey, Script)>, - broadcasted_remote_payment_script: Option<(Script, SecretKey)>, + broadcasted_holder_revokable_script: Option<(Script, PublicKey, PublicKey)>, + counterparty_payment_script: Script, shutdown_script: Script, - onchain_detection: OnchainDetection, - their_htlc_base_key: Option, - their_delayed_payment_base_key: Option, - funding_redeemscript: Option