X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmonitor.rs;h=3f3f06f4064d49908aa3083261d28d2495dc24ba;hb=6662e959c8443fd74c76c2908cfb0c78ec4f906a;hp=b054258319485be03ee5ddac0aaa4b8500f6d4e5;hpb=6afda60d8898455a003e7e085e0b6f1c1277d8fa;p=rust-lightning diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index b0542583..3f3f06f4 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,7 +28,6 @@ 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; @@ -29,20 +39,23 @@ 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::{Readable, MaybeReadable, Writer, Writeable, U48}; use util::{byte_utils, events}; +use util::events::Event; -use std::collections::{HashMap, hash_map}; +use std::collections::{HashMap, HashSet, hash_map}; use std::sync::Mutex; use std::{hash,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. @@ -90,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. /// @@ -123,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, } @@ -139,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, @@ -149,7 +188,7 @@ pub struct HTLCUpdate { } impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); -/// A simple implementation of a ManyChannelMonitor and ChainListener. Can be used to create a +/// A simple implementation of a [`chain::Watch`] 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. @@ -159,40 +198,102 @@ impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); /// 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 +/// `OutPoint` as the key, which will give you a [`chain::Watch`] implementation. +/// +/// [`chain::Watch`]: ../../chain/trait.Watch.html +/// +/// (C-not exported) due to an unconstrained generic in `Key` +pub struct ChainMonitor where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, - C::Target: ChainWatchInterface, { - #[cfg(test)] // Used in ChannelManager tests to manipulate channels directly + /// The monitors pub monitors: Mutex>>, - #[cfg(not(test))] - monitors: Mutex>>, - chain_monitor: C, + watch_events: Mutex, broadcaster: T, logger: L, fee_estimator: F } -impl - 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, L::Target: Logger, - C::Target: ChainWatchInterface, { - 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, &*self.logger); + 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); } } } @@ -200,47 +301,47 @@ impl SimpleManyChannelMonitor +impl ChainMonitor where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, - C::Target: ChainWatchInterface, { /// 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: C, broadcaster: T, logger: L, feeest: F) -> SimpleManyChannelMonitor { - let res = SimpleManyChannelMonitor { + pub fn new(broadcaster: T, logger: L, feeest: F) -> ChainMonitor { + 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> { + fn add_monitor_by_key(&self, key: Key, 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")), hash_map::Entry::Vacant(e) => e, }; - log_trace!(self.logger, "Got new Channel Monitor for channel {}", log_bytes!(monitor.funding_info.0.to_channel_id()[..])); - self.chain_monitor.install_watch_tx(&monitor.funding_info.0.txid, &monitor.funding_info.1); - self.chain_monitor.install_watch_outpoint((monitor.funding_info.0.txid, monitor.funding_info.0.index as u32), &monitor.funding_info.1); - 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); @@ -248,7 +349,7 @@ impl Result<(), MonitorUpdateError> { + fn update_monitor_by_key(&self, key: Key, update: ChannelMonitorUpdate) -> Result<(), MonitorUpdateError> { let mut monitors = self.monitors.lock().unwrap(); match monitors.get_mut(&key) { Some(orig_monitor) => { @@ -260,44 +361,42 @@ impl ManyChannelMonitor for SimpleManyChannelMonitor +impl chain::Watch for ChainMonitor where T::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, - C::Target: ChainWatchInterface, { type Keys = ChanSigner; - fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { + fn watch_channel(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { match self.add_monitor_by_key(funding_txo, monitor) { Ok(_) => Ok(()), Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), } } - fn update_monitor(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr> { + fn update_channel(&self, funding_txo: OutPoint, update: ChannelMonitorUpdate) -> Result<(), ChannelMonitorUpdateErr> { match self.update_monitor_by_key(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, L::Target: Logger, - C::Target: ChainWatchInterface, { - 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()); @@ -306,6 +405,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; @@ -358,7 +467,7 @@ pub(crate) const ANTI_REORG_DELAY: u32 = 6; 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: Txid, revocation_key: PublicKey, @@ -366,30 +475,90 @@ struct LocalSignedTx { 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, }, @@ -401,23 +570,26 @@ pub(crate) enum InputMaterial { 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))?; @@ -435,37 +607,43 @@ 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, } @@ -524,11 +702,11 @@ const MIN_SERIALIZATION_VERSION: u8 = 1; #[cfg_attr(test, derive(PartialEq))] #[derive(Clone)] pub(super) enum ChannelMonitorUpdateStep { - LatestLocalCommitmentTXInfo { - commitment_tx: LocalCommitmentTransaction, + 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, @@ -541,10 +719,10 @@ pub(super) enum ChannelMonitorUpdateStep { idx: u64, secret: [u8; 32], }, - /// 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, }, @@ -553,7 +731,7 @@ 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 htlc_outputs } => { + &ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { ref commitment_tx, ref htlc_outputs } => { 0u8.write(w)?; commitment_tx.write(w)?; (htlc_outputs.len() as u64).write(w)?; @@ -563,7 +741,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)?; @@ -595,7 +773,7 @@ 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)?, htlc_outputs: { let len: u64 = Readable::read(r)?; @@ -608,7 +786,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)?, @@ -650,7 +828,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 { @@ -658,57 +836,55 @@ pub struct ChannelMonitor { commitment_transaction_number_obscure_factor: u64, destination_script: Script, - broadcasted_local_revokable_script: Option<(Script, SecretKey, Script)>, - remote_payment_script: Script, + broadcasted_holder_revokable_script: Option<(Script, PublicKey, PublicKey)>, + counterparty_payment_script: Script, shutdown_script: Script, keys: ChanSigner, funding_info: (OutPoint, Script), - current_remote_commitment_txid: Option, - prev_remote_commitment_txid: Option, + current_counterparty_commitment_txid: Option, + prev_counterparty_commitment_txid: Option, - their_htlc_base_key: PublicKey, - their_delayed_payment_base_key: PublicKey, + counterparty_tx_cache: CounterpartyCommitmentTransaction, 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)>, - our_to_self_delay: u16, - their_to_self_delay: u16, + on_holder_tx_csv: u16, commitment_secrets: CounterpartyCommitmentSecrets, - remote_claimable_outpoints: HashMap>)>>, + counterparty_claimable_outpoints: HashMap>)>>, /// We cannot identify HTLC-Success or HTLC-Timeout transactions by themselves on the chain. /// Nor can we figure out their commitment numbers without the commitment transaction they are - /// spending. Thus, in order to claim them via revocation key, we track all the remote + /// spending. Thus, in order to claim them via revocation key, we track all the counterparty /// commitment transactions which we find on-chain, mapping them to the commitment number which /// can be used to derive the revocation key and claim the transactions. - remote_commitment_txn_on_chain: HashMap)>, + counterparty_commitment_txn_on_chain: HashMap)>, /// Cache used to make pruning of payment_preimages faster. - /// Maps payment_hash values to commitment numbers for remote transactions for non-revoked - /// remote transactions (ie should remain pretty small). + /// Maps payment_hash values to commitment numbers for counterparty transactions for non-revoked + /// counterparty transactions (ie should remain pretty small). /// Serialized to disk but should generally not be sent to Watchtowers. - remote_hash_commitment_number: HashMap, + counterparty_hash_commitment_number: HashMap, - // We store two local commitment transactions to avoid any race conditions where we may update + // We store two holder commitment transactions to avoid any race conditions where we may update // some monitors (potentially on watchtowers) but then fail to update others, resulting in the - // various monitors for one channel being out of sync, and us broadcasting a local + // various monitors for one channel being out of sync, and us broadcasting a holder // transaction for which we have deleted claim information on some watchtowers. - prev_local_signed_commitment_tx: Option, - current_local_commitment_tx: LocalSignedTx, + prev_holder_signed_commitment_tx: Option, + current_holder_commitment_tx: HolderSignedTx, // Used just for ChannelManager to make sure it has the latest channel data during // deserialization - current_remote_commitment_number: u64, + current_counterparty_commitment_number: u64, // Used just for ChannelManager to make sure it has the latest channel data during // deserialization - current_local_commitment_number: u64, + current_holder_commitment_number: u64, payment_preimages: HashMap, - pending_htlcs_updated: Vec, - pending_events: Vec, + pending_monitor_events: Vec, + pending_events: Vec, // Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which // we have to take actions once they reach enough confs. Key is a block height timer, i.e we enforce @@ -727,88 +903,28 @@ pub struct ChannelMonitor { onchain_tx_handler: OnchainTxHandler, // This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the - // channel has been force-closed. After this is set, no further local commitment transaction + // channel has been force-closed. After this is set, no further holder commitment transaction // updates may occur, and we panic!() if one is provided. lockdown_from_offchain: bool, - // Set once we've signed a local commitment transaction and handed it over to our - // OnchainTxHandler. After this is set, no future updates to our local commitment transactions + // Set once we've signed a holder commitment transaction and handed it over to our + // OnchainTxHandler. After this is set, no future updates to our holder commitment transactions // may occur, and we fail any such monitor updates. - local_tx_signed: bool, + // + // In case of update rejection due to a locally already signed commitment transaction, we + // nevertheless store update content to track in case of concurrent broadcast by another + // remote monitor out-of-order with regards to the block view. + holder_tx_signed: bool, // We simply modify last_block_hash in Channel's block_connected so that serialization is // consistent but hopefully the users' copy handles block_connected in a consistent way. // (we do *not*, however, update them in update_monitor to ensure any local user copies keep // their last_block_hash from its state and not based on updated copies that didn't run through // the full block_connected). - pub(crate) last_block_hash: BlockHash, + last_block_hash: BlockHash, secp_ctx: Secp256k1, //TODO: dedup this a bit... } -/// 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(). -/// -/// 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! -/// -/// 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 { - /// The concrete type which signs for transactions and provides access to our channel public - /// keys. - type Keys: ChannelKeys; - - /// 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; -} - #[cfg(any(test, feature = "fuzztarget"))] /// Used only in testing and fuzztarget to check serialization roundtrips don't change the /// underlying object @@ -817,34 +933,32 @@ impl PartialEq for ChannelMonitor { if self.latest_update_id != other.latest_update_id || self.commitment_transaction_number_obscure_factor != other.commitment_transaction_number_obscure_factor || self.destination_script != other.destination_script || - self.broadcasted_local_revokable_script != other.broadcasted_local_revokable_script || - self.remote_payment_script != other.remote_payment_script || + self.broadcasted_holder_revokable_script != other.broadcasted_holder_revokable_script || + self.counterparty_payment_script != other.counterparty_payment_script || self.keys.pubkeys() != other.keys.pubkeys() || self.funding_info != other.funding_info || - self.current_remote_commitment_txid != other.current_remote_commitment_txid || - self.prev_remote_commitment_txid != other.prev_remote_commitment_txid || - self.their_htlc_base_key != other.their_htlc_base_key || - self.their_delayed_payment_base_key != other.their_delayed_payment_base_key || + self.current_counterparty_commitment_txid != other.current_counterparty_commitment_txid || + self.prev_counterparty_commitment_txid != other.prev_counterparty_commitment_txid || + self.counterparty_tx_cache != other.counterparty_tx_cache || 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.our_to_self_delay != other.our_to_self_delay || - self.their_to_self_delay != other.their_to_self_delay || + self.on_holder_tx_csv != other.on_holder_tx_csv || self.commitment_secrets != other.commitment_secrets || - self.remote_claimable_outpoints != other.remote_claimable_outpoints || - self.remote_commitment_txn_on_chain != other.remote_commitment_txn_on_chain || - self.remote_hash_commitment_number != other.remote_hash_commitment_number || - self.prev_local_signed_commitment_tx != other.prev_local_signed_commitment_tx || - self.current_remote_commitment_number != other.current_remote_commitment_number || - self.current_local_commitment_number != other.current_local_commitment_number || - self.current_local_commitment_tx != other.current_local_commitment_tx || + self.counterparty_claimable_outpoints != other.counterparty_claimable_outpoints || + self.counterparty_commitment_txn_on_chain != other.counterparty_commitment_txn_on_chain || + self.counterparty_hash_commitment_number != other.counterparty_hash_commitment_number || + self.prev_holder_signed_commitment_tx != other.prev_holder_signed_commitment_tx || + self.current_counterparty_commitment_number != other.current_counterparty_commitment_number || + self.current_holder_commitment_number != other.current_holder_commitment_number || + self.current_holder_commitment_tx != other.current_holder_commitment_tx || self.payment_preimages != other.payment_preimages || - self.pending_htlcs_updated != other.pending_htlcs_updated || + self.pending_monitor_events != other.pending_monitor_events || self.pending_events.len() != other.pending_events.len() || // We trust events to round-trip properly self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf || self.outputs_to_watch != other.outputs_to_watch || self.lockdown_from_offchain != other.lockdown_from_offchain || - self.local_tx_signed != other.local_tx_signed + self.holder_tx_signed != other.holder_tx_signed { false } else { @@ -861,7 +975,7 @@ impl ChannelMonitor { /// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the /// returned block hash and the the current chain and then reconnecting blocks to get to the /// best chain) upon deserializing the object! - pub fn write_for_disk(&self, writer: &mut W) -> Result<(), ::std::io::Error> { + pub fn write_for_disk(&self, writer: &mut W) -> Result<(), Error> { //TODO: We still write out all the serialization here manually instead of using the fancy //serialization framework we have, we should migrate things over to it. writer.write_all(&[SERIALIZATION_VERSION; 1])?; @@ -873,27 +987,26 @@ impl ChannelMonitor { U48(self.commitment_transaction_number_obscure_factor).write(writer)?; self.destination_script.write(writer)?; - if let Some(ref broadcasted_local_revokable_script) = self.broadcasted_local_revokable_script { + if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script { writer.write_all(&[0; 1])?; - broadcasted_local_revokable_script.0.write(writer)?; - broadcasted_local_revokable_script.1.write(writer)?; - broadcasted_local_revokable_script.2.write(writer)?; + broadcasted_holder_revokable_script.0.write(writer)?; + broadcasted_holder_revokable_script.1.write(writer)?; + broadcasted_holder_revokable_script.2.write(writer)?; } else { writer.write_all(&[1; 1])?; } - self.remote_payment_script.write(writer)?; + self.counterparty_payment_script.write(writer)?; self.shutdown_script.write(writer)?; self.keys.write(writer)?; writer.write_all(&self.funding_info.0.txid[..])?; writer.write_all(&byte_utils::be16_to_array(self.funding_info.0.index))?; self.funding_info.1.write(writer)?; - self.current_remote_commitment_txid.write(writer)?; - self.prev_remote_commitment_txid.write(writer)?; + self.current_counterparty_commitment_txid.write(writer)?; + self.prev_counterparty_commitment_txid.write(writer)?; - writer.write_all(&self.their_htlc_base_key.serialize())?; - writer.write_all(&self.their_delayed_payment_base_key.serialize())?; + self.counterparty_tx_cache.write(writer)?; self.funding_redeemscript.write(writer)?; self.channel_value_satoshis.write(writer)?; @@ -915,8 +1028,7 @@ impl ChannelMonitor { }, } - writer.write_all(&byte_utils::be16_to_array(self.our_to_self_delay))?; - writer.write_all(&byte_utils::be16_to_array(self.their_to_self_delay))?; + writer.write_all(&byte_utils::be16_to_array(self.on_holder_tx_csv))?; self.commitment_secrets.write(writer)?; @@ -930,8 +1042,8 @@ impl ChannelMonitor { } } - writer.write_all(&byte_utils::be64_to_array(self.remote_claimable_outpoints.len() as u64))?; - for (ref txid, ref htlc_infos) in self.remote_claimable_outpoints.iter() { + writer.write_all(&byte_utils::be64_to_array(self.counterparty_claimable_outpoints.len() as u64))?; + for (ref txid, ref htlc_infos) in self.counterparty_claimable_outpoints.iter() { 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() { @@ -940,8 +1052,8 @@ impl ChannelMonitor { } } - writer.write_all(&byte_utils::be64_to_array(self.remote_commitment_txn_on_chain.len() as u64))?; - for (ref txid, &(commitment_number, ref txouts)) in self.remote_commitment_txn_on_chain.iter() { + writer.write_all(&byte_utils::be64_to_array(self.counterparty_commitment_txn_on_chain.len() as u64))?; + for (ref txid, &(commitment_number, ref txouts)) in self.counterparty_commitment_txn_on_chain.iter() { writer.write_all(&txid[..])?; writer.write_all(&byte_utils::be48_to_array(commitment_number))?; (txouts.len() as u64).write(writer)?; @@ -950,24 +1062,24 @@ impl ChannelMonitor { } } - writer.write_all(&byte_utils::be64_to_array(self.remote_hash_commitment_number.len() as u64))?; - for (ref payment_hash, commitment_number) in self.remote_hash_commitment_number.iter() { + writer.write_all(&byte_utils::be64_to_array(self.counterparty_hash_commitment_number.len() as u64))?; + for (ref payment_hash, commitment_number) in self.counterparty_hash_commitment_number.iter() { writer.write_all(&payment_hash.0[..])?; writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; } - macro_rules! serialize_local_tx { - ($local_tx: expr) => { - $local_tx.txid.write(writer)?; - writer.write_all(&$local_tx.revocation_key.serialize())?; - writer.write_all(&$local_tx.a_htlc_key.serialize())?; - writer.write_all(&$local_tx.b_htlc_key.serialize())?; - writer.write_all(&$local_tx.delayed_payment_key.serialize())?; - writer.write_all(&$local_tx.per_commitment_point.serialize())?; + macro_rules! serialize_holder_tx { + ($holder_tx: expr) => { + $holder_tx.txid.write(writer)?; + writer.write_all(&$holder_tx.revocation_key.serialize())?; + writer.write_all(&$holder_tx.a_htlc_key.serialize())?; + writer.write_all(&$holder_tx.b_htlc_key.serialize())?; + writer.write_all(&$holder_tx.delayed_payment_key.serialize())?; + writer.write_all(&$holder_tx.per_commitment_point.serialize())?; - writer.write_all(&byte_utils::be64_to_array($local_tx.feerate_per_kw))?; - writer.write_all(&byte_utils::be64_to_array($local_tx.htlc_outputs.len() as u64))?; - for &(ref htlc_output, ref sig, ref htlc_source) in $local_tx.htlc_outputs.iter() { + writer.write_all(&byte_utils::be32_to_array($holder_tx.feerate_per_kw))?; + writer.write_all(&byte_utils::be64_to_array($holder_tx.htlc_outputs.len() as u64))?; + for &(ref htlc_output, ref sig, ref htlc_source) in $holder_tx.htlc_outputs.iter() { serialize_htlc_in_commitment!(htlc_output); if let &Some(ref their_sig) = sig { 1u8.write(writer)?; @@ -980,26 +1092,32 @@ impl ChannelMonitor { } } - if let Some(ref prev_local_tx) = self.prev_local_signed_commitment_tx { + if let Some(ref prev_holder_tx) = self.prev_holder_signed_commitment_tx { writer.write_all(&[1; 1])?; - serialize_local_tx!(prev_local_tx); + serialize_holder_tx!(prev_holder_tx); } else { writer.write_all(&[0; 1])?; } - serialize_local_tx!(self.current_local_commitment_tx); + serialize_holder_tx!(self.current_holder_commitment_tx); - writer.write_all(&byte_utils::be48_to_array(self.current_remote_commitment_number))?; - writer.write_all(&byte_utils::be48_to_array(self.current_local_commitment_number))?; + writer.write_all(&byte_utils::be48_to_array(self.current_counterparty_commitment_number))?; + writer.write_all(&byte_utils::be48_to_array(self.current_holder_commitment_number))?; writer.write_all(&byte_utils::be64_to_array(self.payment_preimages.len() as u64))?; for payment_preimage in self.payment_preimages.values() { writer.write_all(&payment_preimage.0[..])?; } - writer.write_all(&byte_utils::be64_to_array(self.pending_htlcs_updated.len() as u64))?; - for data in self.pending_htlcs_updated.iter() { - data.write(writer)?; + writer.write_all(&byte_utils::be64_to_array(self.pending_monitor_events.len() as u64))?; + for event in self.pending_monitor_events.iter() { + match event { + MonitorEvent::HTLCEvent(upd) => { + 0u8.write(writer)?; + upd.write(writer)?; + }, + MonitorEvent::CommitmentTxBroadcasted(_) => 1u8.write(writer)? + } } writer.write_all(&byte_utils::be64_to_array(self.pending_events.len() as u64))?; @@ -1039,7 +1157,7 @@ impl ChannelMonitor { self.onchain_tx_handler.write(writer)?; self.lockdown_from_offchain.write(writer)?; - self.local_tx_signed.write(writer)?; + self.holder_tx_signed.write(writer)?; Ok(()) } @@ -1047,74 +1165,69 @@ impl ChannelMonitor { impl ChannelMonitor { pub(super) fn new(keys: ChanSigner, shutdown_pubkey: &PublicKey, - our_to_self_delay: u16, destination_script: &Script, funding_info: (OutPoint, Script), - their_htlc_base_key: &PublicKey, their_delayed_payment_base_key: &PublicKey, - their_to_self_delay: u16, funding_redeemscript: Script, channel_value_satoshis: u64, + on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script), + counterparty_htlc_base_key: &PublicKey, counterparty_delayed_payment_base_key: &PublicKey, + on_holder_tx_csv: u16, funding_redeemscript: Script, channel_value_satoshis: u64, commitment_transaction_number_obscure_factor: u64, - initial_local_commitment_tx: LocalCommitmentTransaction) -> ChannelMonitor { + initial_holder_commitment_tx: HolderCommitmentTransaction) -> ChannelMonitor { assert!(commitment_transaction_number_obscure_factor <= (1 << 48)); let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize()); let shutdown_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_close_key_hash[..]).into_script(); let payment_key_hash = WPubkeyHash::hash(&keys.pubkeys().payment_point.serialize()); - let remote_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script(); - - let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), their_to_self_delay); - - let local_tx_sequence = initial_local_commitment_tx.unsigned_tx.input[0].sequence as u64; - let local_tx_locktime = initial_local_commitment_tx.unsigned_tx.lock_time as u64; - let local_commitment_tx = LocalSignedTx { - txid: initial_local_commitment_tx.txid(), - revocation_key: initial_local_commitment_tx.local_keys.revocation_key, - a_htlc_key: initial_local_commitment_tx.local_keys.a_htlc_key, - b_htlc_key: initial_local_commitment_tx.local_keys.b_htlc_key, - delayed_payment_key: initial_local_commitment_tx.local_keys.a_delayed_payment_key, - per_commitment_point: initial_local_commitment_tx.local_keys.per_commitment_point, - feerate_per_kw: initial_local_commitment_tx.feerate_per_kw, + let counterparty_payment_script = Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_key_hash[..]).into_script(); + + let counterparty_tx_cache = CounterpartyCommitmentTransaction { counterparty_delayed_payment_base_key: *counterparty_delayed_payment_base_key, counterparty_htlc_base_key: *counterparty_htlc_base_key, on_counterparty_tx_csv, per_htlc: HashMap::new() }; + + let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys.clone(), on_holder_tx_csv); + + let holder_tx_sequence = initial_holder_commitment_tx.unsigned_tx.input[0].sequence as u64; + let holder_tx_locktime = initial_holder_commitment_tx.unsigned_tx.lock_time as u64; + let holder_commitment_tx = HolderSignedTx { + txid: initial_holder_commitment_tx.txid(), + revocation_key: initial_holder_commitment_tx.keys.revocation_key, + a_htlc_key: initial_holder_commitment_tx.keys.broadcaster_htlc_key, + b_htlc_key: initial_holder_commitment_tx.keys.countersignatory_htlc_key, + delayed_payment_key: initial_holder_commitment_tx.keys.broadcaster_delayed_payment_key, + per_commitment_point: initial_holder_commitment_tx.keys.per_commitment_point, + feerate_per_kw: initial_holder_commitment_tx.feerate_per_kw, htlc_outputs: Vec::new(), // There are never any HTLCs in the initial commitment transactions }; - // Returning a monitor error before updating tracking points means in case of using - // a concurrent watchtower implementation for same channel, if this one doesn't - // reject update as we do, you MAY have the latest local valid commitment tx onchain - // for which you want to spend outputs. We're NOT robust again this scenario right - // now but we should consider it later. - onchain_tx_handler.provide_latest_local_tx(initial_local_commitment_tx).unwrap(); + onchain_tx_handler.provide_latest_holder_tx(initial_holder_commitment_tx); ChannelMonitor { latest_update_id: 0, commitment_transaction_number_obscure_factor, destination_script: destination_script.clone(), - broadcasted_local_revokable_script: None, - remote_payment_script, + broadcasted_holder_revokable_script: None, + counterparty_payment_script, shutdown_script, keys, funding_info, - current_remote_commitment_txid: None, - prev_remote_commitment_txid: None, + current_counterparty_commitment_txid: None, + prev_counterparty_commitment_txid: None, - their_htlc_base_key: their_htlc_base_key.clone(), - their_delayed_payment_base_key: their_delayed_payment_base_key.clone(), + counterparty_tx_cache, funding_redeemscript, channel_value_satoshis: channel_value_satoshis, their_cur_revocation_points: None, - our_to_self_delay, - their_to_self_delay, + on_holder_tx_csv, commitment_secrets: CounterpartyCommitmentSecrets::new(), - remote_claimable_outpoints: HashMap::new(), - remote_commitment_txn_on_chain: HashMap::new(), - remote_hash_commitment_number: HashMap::new(), + counterparty_claimable_outpoints: HashMap::new(), + counterparty_commitment_txn_on_chain: HashMap::new(), + counterparty_hash_commitment_number: HashMap::new(), - prev_local_signed_commitment_tx: None, - current_local_commitment_tx: local_commitment_tx, - current_remote_commitment_number: 1 << 48, - current_local_commitment_number: 0xffff_ffff_ffff - ((((local_tx_sequence & 0xffffff) << 3*8) | (local_tx_locktime as u64 & 0xffffff)) ^ commitment_transaction_number_obscure_factor), + prev_holder_signed_commitment_tx: None, + current_holder_commitment_tx: holder_commitment_tx, + current_counterparty_commitment_number: 1 << 48, + current_holder_commitment_number: 0xffff_ffff_ffff - ((((holder_tx_sequence & 0xffffff) << 3*8) | (holder_tx_locktime as u64 & 0xffffff)) ^ commitment_transaction_number_obscure_factor), payment_preimages: HashMap::new(), - pending_htlcs_updated: Vec::new(), + pending_monitor_events: Vec::new(), pending_events: Vec::new(), onchain_events_waiting_threshold_conf: HashMap::new(), @@ -1123,7 +1236,7 @@ impl ChannelMonitor { onchain_tx_handler, lockdown_from_offchain: false, - local_tx_signed: false, + holder_tx_signed: false, last_block_hash: Default::default(), secp_ctx: Secp256k1::new(), @@ -1131,48 +1244,48 @@ impl ChannelMonitor { } /// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither - /// needed by local commitment transactions HTCLs nor by remote ones. Unless we haven't already seen remote - /// commitment transaction's secret, they are de facto pruned (we can use revocation key). + /// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen + /// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key). pub(super) fn provide_secret(&mut self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> { if let Err(()) = self.commitment_secrets.provide_secret(idx, secret) { return Err(MonitorUpdateError("Previous secret did not match new one")); } - // Prune HTLCs from the previous remote commitment tx so we don't generate failure/fulfill + // Prune HTLCs from the previous counterparty commitment tx so we don't generate failure/fulfill // events for now-revoked/fulfilled HTLCs. - if let Some(txid) = self.prev_remote_commitment_txid.take() { - for &mut (_, ref mut source) in self.remote_claimable_outpoints.get_mut(&txid).unwrap() { + if let Some(txid) = self.prev_counterparty_commitment_txid.take() { + for &mut (_, ref mut source) in self.counterparty_claimable_outpoints.get_mut(&txid).unwrap() { *source = None; } } if !self.payment_preimages.is_empty() { - let cur_local_signed_commitment_tx = &self.current_local_commitment_tx; - let prev_local_signed_commitment_tx = self.prev_local_signed_commitment_tx.as_ref(); + let cur_holder_signed_commitment_tx = &self.current_holder_commitment_tx; + let prev_holder_signed_commitment_tx = self.prev_holder_signed_commitment_tx.as_ref(); let min_idx = self.get_min_seen_secret(); - let remote_hash_commitment_number = &mut self.remote_hash_commitment_number; + let counterparty_hash_commitment_number = &mut self.counterparty_hash_commitment_number; self.payment_preimages.retain(|&k, _| { - for &(ref htlc, _, _) in cur_local_signed_commitment_tx.htlc_outputs.iter() { + for &(ref htlc, _, _) in cur_holder_signed_commitment_tx.htlc_outputs.iter() { if k == htlc.payment_hash { return true } } - if let Some(prev_local_commitment_tx) = prev_local_signed_commitment_tx { - for &(ref htlc, _, _) in prev_local_commitment_tx.htlc_outputs.iter() { + if let Some(prev_holder_commitment_tx) = prev_holder_signed_commitment_tx { + for &(ref htlc, _, _) in prev_holder_commitment_tx.htlc_outputs.iter() { if k == htlc.payment_hash { return true } } } - let contains = if let Some(cn) = remote_hash_commitment_number.get(&k) { + let contains = if let Some(cn) = counterparty_hash_commitment_number.get(&k) { if *cn < min_idx { return true } true } else { false }; if contains { - remote_hash_commitment_number.remove(&k); + counterparty_hash_commitment_number.remove(&k); } false }); @@ -1181,27 +1294,27 @@ impl ChannelMonitor { Ok(()) } - /// Informs this monitor of the latest remote (ie non-broadcastable) commitment transaction. + /// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction. /// The monitor watches for it to be broadcasted and then uses the HTLC information (and /// possibly future revocation/preimage information) to claim outputs where possible. /// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers. - pub(super) fn provide_latest_remote_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, their_revocation_point: PublicKey, logger: &L) where L::Target: Logger { + pub(super) fn provide_latest_counterparty_commitment_tx_info(&mut self, unsigned_commitment_tx: &Transaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, commitment_number: u64, their_revocation_point: PublicKey, logger: &L) where L::Target: Logger { // TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction // so that a remote monitor doesn't learn anything unless there is a malicious close. // (only maybe, sadly we cant do the same for local info, as we need to be aware of // timeouts) for &(ref htlc, _) in &htlc_outputs { - self.remote_hash_commitment_number.insert(htlc.payment_hash, commitment_number); + self.counterparty_hash_commitment_number.insert(htlc.payment_hash, commitment_number); } let new_txid = unsigned_commitment_tx.txid(); - log_trace!(logger, "Tracking new remote commitment transaction with txid {} at commitment number {} with {} HTLC outputs", new_txid, commitment_number, htlc_outputs.len()); - log_trace!(logger, "New potential remote commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx)); - self.prev_remote_commitment_txid = self.current_remote_commitment_txid.take(); - self.current_remote_commitment_txid = Some(new_txid); - self.remote_claimable_outpoints.insert(new_txid, htlc_outputs); - self.current_remote_commitment_number = commitment_number; - //TODO: Merge this into the other per-remote-transaction output storage stuff + log_trace!(logger, "Tracking new counterparty commitment transaction with txid {} at commitment number {} with {} HTLC outputs", new_txid, commitment_number, htlc_outputs.len()); + log_trace!(logger, "New potential counterparty commitment transaction: {}", encode::serialize_hex(unsigned_commitment_tx)); + self.prev_counterparty_commitment_txid = self.current_counterparty_commitment_txid.take(); + self.current_counterparty_commitment_txid = Some(new_txid); + self.counterparty_claimable_outpoints.insert(new_txid, htlc_outputs.clone()); + self.current_counterparty_commitment_number = commitment_number; + //TODO: Merge this into the other per-counterparty-transaction output storage stuff match self.their_cur_revocation_points { Some(old_points) => { if old_points.0 == commitment_number + 1 { @@ -1220,41 +1333,41 @@ impl ChannelMonitor { self.their_cur_revocation_points = Some((commitment_number, their_revocation_point, None)); } } + let mut htlcs = Vec::with_capacity(htlc_outputs.len()); + for htlc in htlc_outputs { + if htlc.0.transaction_output_index.is_some() { + htlcs.push(htlc.0); + } + } + self.counterparty_tx_cache.per_htlc.insert(new_txid, htlcs); } - /// Informs this monitor of the latest local (ie broadcastable) commitment transaction. The + /// Informs this monitor of the latest holder (ie broadcastable) commitment transaction. The /// monitor watches for timeouts and may broadcast it if we approach such a timeout. Thus, it /// is important that any clones of this channel monitor (including remote clones) by kept - /// up-to-date as our local commitment transaction is updated. - /// Panics if set_their_to_self_delay has never been called. - pub(super) fn provide_latest_local_commitment_tx_info(&mut self, commitment_tx: LocalCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>) -> Result<(), MonitorUpdateError> { - if self.local_tx_signed { - return Err(MonitorUpdateError("A local commitment tx has already been signed, no new local commitment txn can be sent to our counterparty")); - } + /// up-to-date as our holder commitment transaction is updated. + /// Panics if set_on_holder_tx_csv has never been called. + pub(super) fn provide_latest_holder_commitment_tx_info(&mut self, commitment_tx: HolderCommitmentTransaction, htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>) -> Result<(), MonitorUpdateError> { let txid = commitment_tx.txid(); let sequence = commitment_tx.unsigned_tx.input[0].sequence as u64; let locktime = commitment_tx.unsigned_tx.lock_time as u64; - let mut new_local_commitment_tx = LocalSignedTx { + let mut new_holder_commitment_tx = HolderSignedTx { txid, - revocation_key: commitment_tx.local_keys.revocation_key, - a_htlc_key: commitment_tx.local_keys.a_htlc_key, - b_htlc_key: commitment_tx.local_keys.b_htlc_key, - delayed_payment_key: commitment_tx.local_keys.a_delayed_payment_key, - per_commitment_point: commitment_tx.local_keys.per_commitment_point, + revocation_key: commitment_tx.keys.revocation_key, + a_htlc_key: commitment_tx.keys.broadcaster_htlc_key, + b_htlc_key: commitment_tx.keys.countersignatory_htlc_key, + delayed_payment_key: commitment_tx.keys.broadcaster_delayed_payment_key, + per_commitment_point: commitment_tx.keys.per_commitment_point, feerate_per_kw: commitment_tx.feerate_per_kw, htlc_outputs: htlc_outputs, }; - // Returning a monitor error before updating tracking points means in case of using - // a concurrent watchtower implementation for same channel, if this one doesn't - // reject update as we do, you MAY have the latest local valid commitment tx onchain - // for which you want to spend outputs. We're NOT robust again this scenario right - // now but we should consider it later. - if let Err(_) = self.onchain_tx_handler.provide_latest_local_tx(commitment_tx) { - return Err(MonitorUpdateError("Local commitment signed has already been signed, no further update of LOCAL commitment transaction is allowed")); - } - self.current_local_commitment_number = 0xffff_ffff_ffff - ((((sequence & 0xffffff) << 3*8) | (locktime as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor); - mem::swap(&mut new_local_commitment_tx, &mut self.current_local_commitment_tx); - self.prev_local_signed_commitment_tx = Some(new_local_commitment_tx); + self.onchain_tx_handler.provide_latest_holder_tx(commitment_tx); + self.current_holder_commitment_number = 0xffff_ffff_ffff - ((((sequence & 0xffffff) << 3*8) | (locktime as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor); + mem::swap(&mut new_holder_commitment_tx, &mut self.current_holder_commitment_tx); + self.prev_holder_signed_commitment_tx = Some(new_holder_commitment_tx); + if self.holder_tx_signed { + return Err(MonitorUpdateError("Latest holder commitment signed has already been signed, update is rejected")); + } Ok(()) } @@ -1264,34 +1377,14 @@ impl ChannelMonitor { self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone()); } - pub(super) fn broadcast_latest_local_commitment_txn(&mut self, broadcaster: &B, logger: &L) + pub(super) fn broadcast_latest_holder_commitment_txn(&mut self, broadcaster: &B, logger: &L) where B::Target: BroadcasterInterface, L::Target: Logger, { - for tx in self.get_latest_local_commitment_txn(logger).iter() { + for tx in self.get_latest_holder_commitment_txn(logger).iter() { broadcaster.broadcast_transaction(tx); } - } - - /// Used in Channel to cheat wrt the update_ids since it plays games, will be removed soon! - pub(super) fn update_monitor_ooo(&mut self, mut updates: ChannelMonitorUpdate, logger: &L) -> Result<(), MonitorUpdateError> where L::Target: Logger { - for update in updates.updates.drain(..) { - match update { - ChannelMonitorUpdateStep::LatestLocalCommitmentTXInfo { commitment_tx, htlc_outputs } => { - if self.lockdown_from_offchain { panic!(); } - self.provide_latest_local_commitment_tx_info(commitment_tx, htlc_outputs)? - }, - ChannelMonitorUpdateStep::LatestRemoteCommitmentTXInfo { unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point } => - self.provide_latest_remote_commitment_tx_info(&unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point, logger), - ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => - self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage), - ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => - self.provide_secret(idx, secret)?, - ChannelMonitorUpdateStep::ChannelForceClosed { .. } => {}, - } - } - self.latest_update_id = updates.update_id; - Ok(()) + self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0)); } /// Updates a ChannelMonitor on the basis of some new information provided by the Channel @@ -1307,12 +1400,12 @@ impl ChannelMonitor { } for update in updates.updates.drain(..) { match update { - ChannelMonitorUpdateStep::LatestLocalCommitmentTXInfo { commitment_tx, htlc_outputs } => { + ChannelMonitorUpdateStep::LatestHolderCommitmentTXInfo { commitment_tx, htlc_outputs } => { if self.lockdown_from_offchain { panic!(); } - self.provide_latest_local_commitment_tx_info(commitment_tx, htlc_outputs)? + self.provide_latest_holder_commitment_tx_info(commitment_tx, htlc_outputs)? }, - ChannelMonitorUpdateStep::LatestRemoteCommitmentTXInfo { unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point } => - self.provide_latest_remote_commitment_tx_info(&unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point, logger), + ChannelMonitorUpdateStep::LatestCounterpartyCommitmentTXInfo { unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point } => + self.provide_latest_counterparty_commitment_tx_info(&unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point, logger), ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } => self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage), ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } => @@ -1320,9 +1413,9 @@ impl ChannelMonitor { ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast } => { self.lockdown_from_offchain = true; if should_broadcast { - self.broadcast_latest_local_commitment_txn(broadcaster, logger); + self.broadcast_latest_holder_commitment_txn(broadcaster, logger); } else { - log_error!(logger, "You have a toxic local commitment transaction avaible in channel monitor, read comment in ChannelMonitor::get_latest_local_commitment_txn to be informed of manual action to take"); + log_error!(logger, "You have a toxic holder commitment transaction avaible in channel monitor, read comment in ChannelMonitor::get_latest_holder_commitment_txn to be informed of manual action to take"); } } } @@ -1338,12 +1431,14 @@ impl ChannelMonitor { } /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for. - pub fn get_funding_txo(&self) -> OutPoint { - self.funding_info.0 + pub fn get_funding_txo(&self) -> &(OutPoint, Script) { + &self.funding_info } /// Gets a list of txids, with their output scripts (in the order they appear in the /// transaction), which we must learn about spends of via block_connected(). + /// + /// (C-not exported) because we have no HashMap bindings pub fn get_outputs_to_watch(&self) -> &HashMap> { &self.outputs_to_watch } @@ -1352,9 +1447,11 @@ impl ChannelMonitor { /// Generally useful when deserializing as during normal operation the return values of /// block_connected are sufficient to ensure all relevant outpoints are being monitored (note /// that the get_funding_txo outpoint and transaction must also be monitored for!). + /// + /// (C-not exported) as there is no practical way to track lifetimes of returned values. pub fn get_monitored_outpoints(&self) -> Vec<(Txid, u32, &Script)> { - let mut res = Vec::with_capacity(self.remote_commitment_txn_on_chain.len() * 2); - for (ref txid, &(_, ref outputs)) in self.remote_commitment_txn_on_chain.iter() { + let mut res = Vec::with_capacity(self.counterparty_commitment_txn_on_chain.len() * 2); + for (ref txid, &(_, ref outputs)) in self.counterparty_commitment_txn_on_chain.iter() { for (idx, output) in outputs.iter().enumerate() { res.push(((*txid).clone(), idx as u32, output)); } @@ -1363,20 +1460,22 @@ impl ChannelMonitor { } /// Get the list of HTLCs who's status has been updated on chain. This should be called by - /// ChannelManager via ManyChannelMonitor::get_and_clear_pending_htlcs_updated(). - pub fn get_and_clear_pending_htlcs_updated(&mut self) -> Vec { + /// ChannelManager via [`chain::Watch::release_pending_monitor_events`]. + /// + /// [`chain::Watch::release_pending_monitor_events`]: ../../chain/trait.Watch.html#tymethod.release_pending_monitor_events + pub fn get_and_clear_pending_monitor_events(&mut self) -> Vec { let mut ret = Vec::new(); - mem::swap(&mut ret, &mut self.pending_htlcs_updated); + mem::swap(&mut ret, &mut self.pending_monitor_events); ret } /// Gets the list of pending events which were generated by previous actions, clearing the list /// in the process. /// - /// This is called by ManyChannelMonitor::get_and_clear_pending_events() and is equivalent to + /// This is called by ChainMonitor::get_and_clear_pending_events() and is equivalent to /// EventsProvider::get_and_clear_pending_events() except that it requires &mut self as we do /// no internal locking in ChannelMonitors. - pub fn get_and_clear_pending_events(&mut self) -> Vec { + pub fn get_and_clear_pending_events(&mut self) -> Vec { let mut ret = Vec::new(); mem::swap(&mut ret, &mut self.pending_events); ret @@ -1391,28 +1490,28 @@ impl ChannelMonitor { self.commitment_secrets.get_min_seen_secret() } - pub(super) fn get_cur_remote_commitment_number(&self) -> u64 { - self.current_remote_commitment_number + pub(super) fn get_cur_counterparty_commitment_number(&self) -> u64 { + self.current_counterparty_commitment_number } - pub(super) fn get_cur_local_commitment_number(&self) -> u64 { - self.current_local_commitment_number + pub(super) fn get_cur_holder_commitment_number(&self) -> u64 { + self.current_holder_commitment_number } - /// Attempts to claim a remote commitment transaction's outputs using the revocation key and - /// data in remote_claimable_outpoints. Will directly claim any HTLC outputs which expire at a + /// Attempts to claim a counterparty commitment transaction's outputs using the revocation key and + /// data in counterparty_claimable_outpoints. Will directly claim any HTLC outputs which expire at a /// height > height + CLTV_SHARED_CLAIM_BUFFER. In any case, will install monitoring for /// HTLC-Success/HTLC-Timeout transactions. /// Return updates for HTLC pending in the channel and failed automatically by the broadcast of - /// revoked remote commitment tx - fn check_spend_remote_transaction(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec, (Txid, Vec)) where L::Target: Logger { + /// revoked counterparty commitment tx + fn check_spend_counterparty_transaction(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec, (Txid, Vec)) where L::Target: Logger { // Most secp and related errors trying to create keys means we have no hope of constructing // a spend transaction...so we return no transactions to broadcast let mut claimable_outpoints = Vec::new(); let mut watch_outputs = Vec::new(); let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers! - let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid); + let per_commitment_option = self.counterparty_claimable_outpoints.get(&commitment_txid); macro_rules! ignore_error { ( $thing : expr ) => { @@ -1429,19 +1528,16 @@ impl ChannelMonitor { let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let b_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().htlc_basepoint)); - let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_delayed_payment_base_key)); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.their_htlc_base_key)); + let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key), &self.counterparty_tx_cache.counterparty_delayed_payment_base_key)); - let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); + let revokeable_redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.counterparty_tx_cache.on_counterparty_tx_csv, &delayed_key); let revokeable_p2wsh = revokeable_redeemscript.to_v0_p2wsh(); - // First, process non-htlc outputs (to_local & to_remote) + // First, process non-htlc outputs (to_holder & to_counterparty) for (idx, outp) in tx.output.iter().enumerate() { if outp.script_pubkey == revokeable_p2wsh { - let witness_data = InputMaterial::Revoked { witness_script: revokeable_redeemscript.clone(), pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: outp.value }; - claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); + let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: outp.value, htlc: None, on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv}; + claimable_outpoints.push(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: idx as u32 }, witness_data}); } } @@ -1449,13 +1545,11 @@ impl ChannelMonitor { if let Some(ref per_commitment_data) = per_commitment_option { for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); if transaction_output_index as usize >= tx.output.len() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 || - tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { + tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } - let witness_data = InputMaterial::Revoked { witness_script: expected_script, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: true, amount: tx.output[transaction_output_index as usize].value }; + let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: if htlc.offered { InputDescriptors::RevokedOfferedHTLC } else { InputDescriptors::RevokedReceivedHTLC }, amount: tx.output[transaction_output_index as usize].value, htlc: Some(htlc.clone()), on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv}; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable: true, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@ -1463,17 +1557,17 @@ impl ChannelMonitor { // Last, track onchain revoked commitment transaction and fail backward outgoing HTLCs as payment path is broken if !claimable_outpoints.is_empty() || per_commitment_option.is_some() { // ie we're confident this is actually ours - // We're definitely a remote commitment transaction! - log_trace!(logger, "Got broadcast of revoked remote commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len()); + // We're definitely a counterparty commitment transaction! + log_trace!(logger, "Got broadcast of revoked counterparty commitment transaction, going to generate general spend tx with {} inputs", claimable_outpoints.len()); watch_outputs.append(&mut tx.output.clone()); - self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); + self.counterparty_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); macro_rules! check_htlc_fails { ($txid: expr, $commitment_tx: expr) => { - if let Some(ref outpoints) = self.remote_claimable_outpoints.get($txid) { + if let Some(ref outpoints) = self.counterparty_claimable_outpoints.get($txid) { for &(ref htlc, ref source_option) in outpoints.iter() { if let &Some(ref source) = source_option { - log_info!(logger, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of revoked remote commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1); + log_info!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1); match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) { hash_map::Entry::Occupied(mut entry) => { let e = entry.get_mut(); @@ -1496,30 +1590,30 @@ impl ChannelMonitor { } } } - if let Some(ref txid) = self.current_remote_commitment_txid { + if let Some(ref txid) = self.current_counterparty_commitment_txid { check_htlc_fails!(txid, "current"); } - if let Some(ref txid) = self.prev_remote_commitment_txid { - check_htlc_fails!(txid, "remote"); + if let Some(ref txid) = self.prev_counterparty_commitment_txid { + check_htlc_fails!(txid, "counterparty"); } - // No need to check local commitment txn, symmetric HTLCSource must be present as per-htlc data on remote commitment tx + // No need to check holder commitment txn, symmetric HTLCSource must be present as per-htlc data on counterparty commitment tx } } else if let Some(per_commitment_data) = per_commitment_option { // While this isn't useful yet, there is a potential race where if a counterparty // revokes a state at the same time as the commitment transaction for that state is // confirmed, and the watchtower receives the block before the user, the user could // upload a new ChannelMonitor with the revocation secret but the watchtower has - // already processed the block, resulting in the remote_commitment_txn_on_chain entry + // already processed the block, resulting in the counterparty_commitment_txn_on_chain entry // not being generated by the above conditional. Thus, to be safe, we go ahead and // insert it here. watch_outputs.append(&mut tx.output.clone()); - self.remote_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); + self.counterparty_commitment_txn_on_chain.insert(commitment_txid, (commitment_number, tx.output.iter().map(|output| { output.script_pubkey.clone() }).collect())); - log_trace!(logger, "Got broadcast of non-revoked remote commitment transaction {}", commitment_txid); + log_trace!(logger, "Got broadcast of non-revoked counterparty commitment transaction {}", commitment_txid); macro_rules! check_htlc_fails { ($txid: expr, $commitment_tx: expr, $id: tt) => { - if let Some(ref latest_outpoints) = self.remote_claimable_outpoints.get($txid) { + if let Some(ref latest_outpoints) = self.counterparty_claimable_outpoints.get($txid) { $id: for &(ref htlc, ref source_option) in latest_outpoints.iter() { if let &Some(ref source) = source_option { // Check if the HTLC is present in the commitment transaction that was @@ -1536,7 +1630,7 @@ impl ChannelMonitor { continue $id; } } - log_trace!(logger, "Failing HTLC with payment_hash {} from {} remote commitment tx due to broadcast of remote commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx); + log_trace!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of counterparty commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx); match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) { hash_map::Entry::Occupied(mut entry) => { let e = entry.get_mut(); @@ -1559,10 +1653,10 @@ impl ChannelMonitor { } } } - if let Some(ref txid) = self.current_remote_commitment_txid { + if let Some(ref txid) = self.current_counterparty_commitment_txid { check_htlc_fails!(txid, "current", 'current_loop); } - if let Some(ref txid) = self.prev_remote_commitment_txid { + if let Some(ref txid) = self.prev_counterparty_commitment_txid { check_htlc_fails!(txid, "previous", 'prev_loop); } @@ -1573,24 +1667,24 @@ impl ChannelMonitor { if revocation_points.0 == commitment_number + 1 { Some(point) } else { None } } else { None }; if let Some(revocation_point) = revocation_point_option { - let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, revocation_point, &self.keys.pubkeys().revocation_basepoint)); - let b_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &self.keys.pubkeys().htlc_basepoint)); - let htlc_privkey = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &self.keys.htlc_base_key())); - let a_htlc_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, revocation_point, &self.their_htlc_base_key)); + self.counterparty_payment_script = { + // Note that the Network here is ignored as we immediately drop the address for the + // script_pubkey version + let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize()); + Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script() + }; // Then, try to find htlc outputs for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() { if let Some(transaction_output_index) = htlc.transaction_output_index { - let expected_script = chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey); if transaction_output_index as usize >= tx.output.len() || - tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 || - tx.output[transaction_output_index as usize].script_pubkey != expected_script.to_v0_p2wsh() { + tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 { return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user } let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None }; let aggregable = if !htlc.offered { false } else { true }; if preimage.is_some() || !htlc.offered { - let witness_data = InputMaterial::RemoteHTLC { witness_script: expected_script, key: htlc_privkey, preimage, amount: htlc.amount_msat / 1000, locktime: htlc.cltv_expiry }; + let witness_data = InputMaterial::CounterpartyHTLC { per_commitment_point: *revocation_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, preimage, htlc: htlc.clone() }; claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data }); } } @@ -1601,8 +1695,8 @@ impl ChannelMonitor { (claimable_outpoints, (commitment_txid, watch_outputs)) } - /// Attempts to claim a remote HTLC-Success/HTLC-Timeout's outputs using the revocation key - fn check_spend_remote_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec, Option<(Txid, Vec)>) where L::Target: Logger { + /// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key + fn check_spend_counterparty_htlc(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec, Option<(Txid, Vec)>) where L::Target: Logger { let htlc_txid = tx.txid(); if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 { return (Vec::new(), None) @@ -1620,30 +1714,24 @@ impl ChannelMonitor { let secret = if let Some(secret) = self.get_secret(commitment_number) { secret } else { return (Vec::new(), None); }; let per_commitment_key = ignore_error!(SecretKey::from_slice(&secret)); let per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &per_commitment_key); - let revocation_pubkey = ignore_error!(chan_utils::derive_public_revocation_key(&self.secp_ctx, &per_commitment_point, &self.keys.pubkeys().revocation_basepoint)); - let revocation_key = ignore_error!(chan_utils::derive_private_revocation_key(&self.secp_ctx, &per_commitment_key, &self.keys.revocation_base_key())); - let delayed_key = ignore_error!(chan_utils::derive_public_key(&self.secp_ctx, &per_commitment_point, &self.their_delayed_payment_base_key)); - let redeemscript = chan_utils::get_revokeable_redeemscript(&revocation_pubkey, self.our_to_self_delay, &delayed_key); - - log_trace!(logger, "Remote HTLC broadcast {}:{}", htlc_txid, 0); - let witness_data = InputMaterial::Revoked { witness_script: redeemscript, pubkey: Some(revocation_pubkey), key: revocation_key, is_htlc: false, amount: tx.output[0].value }; - let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.our_to_self_delay as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); + + log_trace!(logger, "Counterparty HTLC broadcast {}:{}", htlc_txid, 0); + let witness_data = InputMaterial::Revoked { per_commitment_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, per_commitment_key, input_descriptor: InputDescriptors::RevokedOutput, amount: tx.output[0].value, htlc: None, on_counterparty_tx_csv: self.counterparty_tx_cache.on_counterparty_tx_csv }; + let claimable_outpoints = vec!(ClaimRequest { absolute_timelock: height + self.counterparty_tx_cache.on_counterparty_tx_csv as u32, aggregable: true, outpoint: BitcoinOutPoint { txid: htlc_txid, vout: 0}, witness_data }); (claimable_outpoints, Some((htlc_txid, tx.output.clone()))) } - fn broadcast_by_local_state(&self, commitment_tx: &Transaction, local_tx: &LocalSignedTx) -> (Vec, Vec, Option<(Script, SecretKey, Script)>) { - let mut claim_requests = Vec::with_capacity(local_tx.htlc_outputs.len()); - let mut watch_outputs = Vec::with_capacity(local_tx.htlc_outputs.len()); + fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx) -> (Vec, Vec, Option<(Script, PublicKey, PublicKey)>) { + let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len()); + let mut watch_outputs = Vec::with_capacity(holder_tx.htlc_outputs.len()); - let redeemscript = chan_utils::get_revokeable_redeemscript(&local_tx.revocation_key, self.their_to_self_delay, &local_tx.delayed_payment_key); - let broadcasted_local_revokable_script = if let Ok(local_delayedkey) = chan_utils::derive_private_key(&self.secp_ctx, &local_tx.per_commitment_point, self.keys.delayed_payment_base_key()) { - Some((redeemscript.to_v0_p2wsh(), local_delayedkey, redeemscript)) - } else { None }; + let redeemscript = chan_utils::get_revokeable_redeemscript(&holder_tx.revocation_key, self.on_holder_tx_csv, &holder_tx.delayed_payment_key); + let broadcasted_holder_revokable_script = Some((redeemscript.to_v0_p2wsh(), holder_tx.per_commitment_point.clone(), holder_tx.revocation_key.clone())); - for &(ref htlc, _, _) in local_tx.htlc_outputs.iter() { + for &(ref htlc, _, _) in holder_tx.htlc_outputs.iter() { if let Some(transaction_output_index) = htlc.transaction_output_index { - claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: local_tx.txid, vout: transaction_output_index as u32 }, - witness_data: InputMaterial::LocalHTLC { + claim_requests.push(ClaimRequest { absolute_timelock: ::std::u32::MAX, aggregable: false, outpoint: BitcoinOutPoint { txid: holder_tx.txid, vout: transaction_output_index as u32 }, + witness_data: InputMaterial::HolderHTLC { preimage: if !htlc.offered { if let Some(preimage) = self.payment_preimages.get(&htlc.payment_hash) { Some(preimage.clone()) @@ -1658,20 +1746,20 @@ impl ChannelMonitor { } } - (claim_requests, watch_outputs, broadcasted_local_revokable_script) + (claim_requests, watch_outputs, broadcasted_holder_revokable_script) } /// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet) - /// revoked using data in local_claimable_outpoints. + /// revoked using data in holder_claimable_outpoints. /// Should not be used if check_spend_revoked_transaction succeeds. - fn check_spend_local_transaction(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec, (Txid, Vec)) where L::Target: Logger { + fn check_spend_holder_transaction(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec, (Txid, Vec)) where L::Target: Logger { let commitment_txid = tx.txid(); let mut claim_requests = Vec::new(); let mut watch_outputs = Vec::new(); macro_rules! wait_threshold_conf { ($height: expr, $source: expr, $commitment_tx: expr, $payment_hash: expr) => { - log_trace!(logger, "Failing HTLC with payment_hash {} from {} local commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1); + log_trace!(logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1); match self.onchain_events_waiting_threshold_conf.entry($height + ANTI_REORG_DELAY - 1) { hash_map::Entry::Occupied(mut entry) => { let e = entry.get_mut(); @@ -1696,30 +1784,30 @@ impl ChannelMonitor { ($updates: expr) => { claim_requests = $updates.0; watch_outputs.append(&mut $updates.1); - self.broadcasted_local_revokable_script = $updates.2; + self.broadcasted_holder_revokable_script = $updates.2; } } - // HTLCs set may differ between last and previous local commitment txn, in case of one them hitting chain, ensure we cancel all HTLCs backward - let mut is_local_tx = false; + // HTLCs set may differ between last and previous holder commitment txn, in case of one them hitting chain, ensure we cancel all HTLCs backward + let mut is_holder_tx = false; - if self.current_local_commitment_tx.txid == commitment_txid { - is_local_tx = true; - log_trace!(logger, "Got latest local commitment tx broadcast, searching for available HTLCs to claim"); - let mut res = self.broadcast_by_local_state(tx, &self.current_local_commitment_tx); + if self.current_holder_commitment_tx.txid == commitment_txid { + is_holder_tx = true; + log_trace!(logger, "Got latest holder commitment tx broadcast, searching for available HTLCs to claim"); + let mut res = self.broadcast_by_holder_state(tx, &self.current_holder_commitment_tx); append_onchain_update!(res); - } else if let &Some(ref local_tx) = &self.prev_local_signed_commitment_tx { - if local_tx.txid == commitment_txid { - is_local_tx = true; - log_trace!(logger, "Got previous local commitment tx broadcast, searching for available HTLCs to claim"); - let mut res = self.broadcast_by_local_state(tx, local_tx); + } else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx { + if holder_tx.txid == commitment_txid { + is_holder_tx = true; + log_trace!(logger, "Got previous holder commitment tx broadcast, searching for available HTLCs to claim"); + let mut res = self.broadcast_by_holder_state(tx, holder_tx); append_onchain_update!(res); } } macro_rules! fail_dust_htlcs_after_threshold_conf { - ($local_tx: expr) => { - for &(ref htlc, _, ref source) in &$local_tx.htlc_outputs { + ($holder_tx: expr) => { + for &(ref htlc, _, ref source) in &$holder_tx.htlc_outputs { if htlc.transaction_output_index.is_none() { if let &Some(ref source) = source { wait_threshold_conf!(height, source.clone(), "lastest", htlc.payment_hash.clone()); @@ -1729,32 +1817,32 @@ impl ChannelMonitor { } } - if is_local_tx { - fail_dust_htlcs_after_threshold_conf!(self.current_local_commitment_tx); - if let &Some(ref local_tx) = &self.prev_local_signed_commitment_tx { - fail_dust_htlcs_after_threshold_conf!(local_tx); + if is_holder_tx { + fail_dust_htlcs_after_threshold_conf!(self.current_holder_commitment_tx); + if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx { + fail_dust_htlcs_after_threshold_conf!(holder_tx); } } (claim_requests, (commitment_txid, watch_outputs)) } - /// Used by ChannelManager deserialization to broadcast the latest local state if its copy of - /// the Channel was out-of-date. You may use it to get a broadcastable local toxic tx in case of - /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our remote side knows - /// a higher revocation secret than the local commitment number we are aware of. Broadcasting these - /// transactions are UNSAFE, as they allow remote side to punish you. Nevertheless you may want to - /// broadcast them if remote don't close channel with his higher commitment transaction after a + /// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of + /// the Channel was out-of-date. You may use it to get a broadcastable holder toxic tx in case of + /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our counterparty side knows + /// a higher revocation secret than the holder commitment number we are aware of. Broadcasting these + /// transactions are UNSAFE, as they allow counterparty side to punish you. Nevertheless you may want to + /// broadcast them if counterparty don't close channel with his higher commitment transaction after a /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact /// out-of-band the other node operator to coordinate with him if option is available to you. /// In any-case, choice is up to the user. - pub fn get_latest_local_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { - log_trace!(logger, "Getting signed latest local commitment transaction!"); - self.local_tx_signed = true; - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) { + pub fn get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { + log_trace!(logger, "Getting signed latest holder commitment transaction!"); + self.holder_tx_signed = true; + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) { let txid = commitment_tx.txid(); let mut res = vec![commitment_tx]; - for htlc in self.current_local_commitment_tx.htlc_outputs.iter() { + for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { if let Some(vout) = htlc.0.transaction_output_index { let preimage = if !htlc.0.offered { if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { @@ -1769,22 +1857,22 @@ impl ChannelMonitor { } } // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do. - // The data will be re-generated and tracked in check_spend_local_transaction if we get a confirmation. + // The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation. return res } Vec::new() } - /// Unsafe test-only version of get_latest_local_commitment_txn used by our test framework - /// to bypass LocalCommitmentTransaction state update lockdown after signature and generate + /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework + /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate /// revoked commitment transaction. - #[cfg(test)] - pub fn unsafe_get_latest_local_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { - log_trace!(logger, "Getting signed copy of latest local commitment transaction!"); - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(&self.funding_redeemscript) { + #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))] + pub fn unsafe_get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { + log_trace!(logger, "Getting signed copy of latest holder commitment transaction!"); + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript) { let txid = commitment_tx.txid(); let mut res = vec![commitment_tx]; - for htlc in self.current_local_commitment_tx.htlc_outputs.iter() { + for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() { if let Some(vout) = htlc.0.transaction_output_index { let preimage = if !htlc.0.offered { if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else { @@ -1803,17 +1891,23 @@ impl ChannelMonitor { Vec::new() } - /// Called by SimpleManyChannelMonitor::block_connected, which implements - /// ChainListener::block_connected. - /// Eventually this should be pub and, roughly, implement ChainListener, however this requires - /// &mut self, as well as returns new spendable outputs and outpoints to watch for spending of - /// on-chain. - fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F, logger: L)-> Vec<(Txid, Vec)> + /// Processes transactions in a newly connected block, which may result in any of the following: + /// - update the monitor's state against resolved HTLCs + /// - punish the counterparty in the case of seeing a revoked commitment transaction + /// - force close the channel and claim/timeout incoming/outgoing HTLCs if near expiration + /// - detect settled outputs for later spending + /// - schedule and bump any in-flight claims + /// + /// Returns any transaction outputs from `txn_matched` that spends of should be watched for. + /// After called these are also available via [`get_outputs_to_watch`]. + /// + /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch + pub fn block_connected(&mut self, header: &BlockHeader, txn_matched: &[(usize, &Transaction)], height: u32, broadcaster: B, fee_estimator: F, logger: L)-> Vec<(Txid, Vec)> where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, { - for tx in txn_matched { + for &(_, tx) in txn_matched { let mut output_val = 0; for out in tx.output.iter() { if out.value > 21_000_000_0000_0000 { panic!("Value-overflowing transaction provided to block connected"); } @@ -1822,10 +1916,12 @@ impl ChannelMonitor { } } + let block_hash = header.block_hash(); log_trace!(logger, "Block {} at height {} connected with {} txn matched", block_hash, height, txn_matched.len()); + let mut watch_outputs = Vec::new(); let mut claimable_outpoints = Vec::new(); - for tx in txn_matched { + for &(_, tx) in txn_matched { if tx.input.len() == 1 { // Assuming our keys were not leaked (in which case we're screwed no matter what), // commitment transactions and HTLC transactions will all only ever have one input, @@ -1834,12 +1930,12 @@ impl ChannelMonitor { let prevout = &tx.input[0].previous_output; if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 { if (tx.input[0].sequence >> 8*3) as u8 == 0x80 && (tx.lock_time >> 8*3) as u8 == 0x20 { - let (mut new_outpoints, new_outputs) = self.check_spend_remote_transaction(&tx, height, &logger); + let (mut new_outpoints, new_outputs) = self.check_spend_counterparty_transaction(&tx, height, &logger); if !new_outputs.1.is_empty() { watch_outputs.push(new_outputs); } if new_outpoints.is_empty() { - let (mut new_outpoints, new_outputs) = self.check_spend_local_transaction(&tx, height, &logger); + let (mut new_outpoints, new_outputs) = self.check_spend_holder_transaction(&tx, height, &logger); if !new_outputs.1.is_empty() { watch_outputs.push(new_outputs); } @@ -1848,8 +1944,8 @@ impl ChannelMonitor { claimable_outpoints.append(&mut new_outpoints); } } else { - if let Some(&(commitment_number, _)) = self.remote_commitment_txn_on_chain.get(&prevout.txid) { - let (mut new_outpoints, new_outputs_option) = self.check_spend_remote_htlc(&tx, commitment_number, height, &logger); + if let Some(&(commitment_number, _)) = self.counterparty_commitment_txn_on_chain.get(&prevout.txid) { + let (mut new_outpoints, new_outputs_option) = self.check_spend_counterparty_htlc(&tx, commitment_number, height, &logger); claimable_outpoints.append(&mut new_outpoints); if let Some(new_outputs) = new_outputs_option { watch_outputs.push(new_outputs); @@ -1869,10 +1965,12 @@ impl ChannelMonitor { claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }}); } if should_broadcast { - if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) { - let (mut new_outpoints, new_outputs, _) = self.broadcast_by_local_state(&commitment_tx, &self.current_local_commitment_tx); + self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0)); + if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) { + self.holder_tx_signed = true; + let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(&commitment_tx, &self.current_holder_commitment_tx); if !new_outputs.is_empty() { - watch_outputs.push((self.current_local_commitment_tx.txid.clone(), new_outputs)); + watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs)); } claimable_outpoints.append(&mut new_outpoints); } @@ -1882,24 +1980,25 @@ impl ChannelMonitor { match ev { OnchainEvent::HTLCUpdate { htlc_update } => { log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0)); - self.pending_htlcs_updated.push(HTLCUpdate { + self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate { payment_hash: htlc_update.1, payment_preimage: None, source: htlc_update.0, - }); + })); }, OnchainEvent::MaturingOutput { descriptor } => { log_trace!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor)); - self.pending_events.push(events::Event::SpendableOutputs { + self.pending_events.push(Event::SpendableOutputs { outputs: vec![descriptor] }); } } } } + self.onchain_tx_handler.block_connected(txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger); - self.last_block_hash = block_hash.clone(); + self.last_block_hash = block_hash; for &(ref txid, ref output_scripts) in watch_outputs.iter() { self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect()); } @@ -1907,12 +2006,16 @@ impl ChannelMonitor { watch_outputs } - fn block_disconnected(&mut self, height: u32, block_hash: &BlockHash, broadcaster: B, fee_estimator: F, logger: L) + /// Determines if the disconnected block contained any transactions of interest and updates + /// appropriately. + pub fn block_disconnected(&mut self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, { + let block_hash = header.block_hash(); log_trace!(logger, "Block {} at height {} disconnected", block_hash, height); + if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) { //We may discard: //- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected @@ -1921,14 +2024,14 @@ impl ChannelMonitor { self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger); - self.last_block_hash = block_hash.clone(); + self.last_block_hash = block_hash; } - pub(super) fn would_broadcast_at_height(&self, height: u32, logger: &L) -> bool where L::Target: Logger { + fn would_broadcast_at_height(&self, height: u32, logger: &L) -> bool where L::Target: Logger { // We need to consider all HTLCs which are: - // * in any unrevoked remote commitment transaction, as they could broadcast said + // * in any unrevoked counterparty commitment transaction, as they could broadcast said // transactions and we'd end up in a race, or - // * are in our latest local commitment transaction, as this is the thing we will + // * are in our latest holder commitment transaction, as this is the thing we will // broadcast if we go on-chain. // Note that we consider HTLCs which were below dust threshold here - while they don't // strictly imply that we need to fail the channel, we need to go ahead and fail them back @@ -1936,7 +2039,7 @@ impl ChannelMonitor { // updates that peer sends us are update_fails, failing the channel if not. It's probably // easier to just fail the channel as this case should be rare enough anyway. macro_rules! scan_commitment { - ($htlcs: expr, $local_tx: expr) => { + ($htlcs: expr, $holder_tx: expr) => { for ref htlc in $htlcs { // For inbound HTLCs which we know the preimage for, we have to ensure we hit the // chain with enough room to claim the HTLC without our counterparty being able to @@ -1961,7 +2064,7 @@ impl ChannelMonitor { // LATENCY_GRACE_PERIOD_BLOCKS + 2*CLTV_CLAIM_BUFFER <= CLTV_EXPIRY_DELTA // The final, above, condition is checked for statically in channelmanager // with CHECK_CLTV_EXPIRY_SANITY_2. - let htlc_outbound = $local_tx == htlc.offered; + let htlc_outbound = $holder_tx == htlc.offered; if ( htlc_outbound && htlc.cltv_expiry + LATENCY_GRACE_PERIOD_BLOCKS <= height) || (!htlc_outbound && htlc.cltv_expiry <= height + CLTV_CLAIM_BUFFER && self.payment_preimages.contains_key(&htlc.payment_hash)) { log_info!(logger, "Force-closing channel due to {} HTLC timeout, HTLC expiry is {}", if htlc_outbound { "outbound" } else { "inbound "}, htlc.cltv_expiry); @@ -1971,15 +2074,15 @@ impl ChannelMonitor { } } - scan_commitment!(self.current_local_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a), true); + scan_commitment!(self.current_holder_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, _)| a), true); - if let Some(ref txid) = self.current_remote_commitment_txid { - if let Some(ref htlc_outputs) = self.remote_claimable_outpoints.get(txid) { + if let Some(ref txid) = self.current_counterparty_commitment_txid { + if let Some(ref htlc_outputs) = self.counterparty_claimable_outpoints.get(txid) { scan_commitment!(htlc_outputs.iter().map(|&(ref a, _)| a), false); } } - if let Some(ref txid) = self.prev_remote_commitment_txid { - if let Some(ref htlc_outputs) = self.remote_claimable_outpoints.get(txid) { + if let Some(ref txid) = self.prev_counterparty_commitment_txid { + if let Some(ref htlc_outputs) = self.counterparty_claimable_outpoints.get(txid) { scan_commitment!(htlc_outputs.iter().map(|&(ref a, _)| a), false); } } @@ -1987,8 +2090,8 @@ impl ChannelMonitor { false } - /// Check if any transaction broadcasted is resolving HTLC output by a success or timeout on a local - /// or remote commitment tx, if so send back the source, preimage if found and payment_hash of resolved HTLC + /// Check if any transaction broadcasted is resolving HTLC output by a success or timeout on a holder + /// or counterparty commitment tx, if so send back the source, preimage if found and payment_hash of resolved HTLC fn is_resolving_htlc_output(&mut self, tx: &Transaction, height: u32, logger: &L) where L::Target: Logger { 'outer_loop: for input in &tx.input { let mut payment_data = None; @@ -1998,13 +2101,13 @@ impl ChannelMonitor { let offered_preimage_claim = input.witness.len() == 3 && HTLCType::scriptlen_to_htlctype(input.witness[2].len()) == Some(HTLCType::OfferedHTLC); macro_rules! log_claim { - ($tx_info: expr, $local_tx: expr, $htlc: expr, $source_avail: expr) => { + ($tx_info: expr, $holder_tx: expr, $htlc: expr, $source_avail: expr) => { // We found the output in question, but aren't failing it backwards - // as we have no corresponding source and no valid remote commitment txid + // as we have no corresponding source and no valid counterparty commitment txid // to try a weak source binding with same-hash, same-value still-valid offered HTLC. // This implies either it is an inbound HTLC or an outbound HTLC on a revoked transaction. - let outbound_htlc = $local_tx == $htlc.offered; - if ($local_tx && revocation_sig_claim) || + let outbound_htlc = $holder_tx == $htlc.offered; + if ($holder_tx && revocation_sig_claim) || (outbound_htlc && !$source_avail && (accepted_preimage_claim || offered_preimage_claim)) { log_error!(logger, "Input spending {} ({}:{}) in {} resolves {} HTLC with payment hash {} with {}!", $tx_info, input.previous_output.txid, input.previous_output.vout, tx.txid(), @@ -2019,13 +2122,13 @@ impl ChannelMonitor { } } - macro_rules! check_htlc_valid_remote { - ($remote_txid: expr, $htlc_output: expr) => { - if let Some(txid) = $remote_txid { - for &(ref pending_htlc, ref pending_source) in self.remote_claimable_outpoints.get(&txid).unwrap() { + macro_rules! check_htlc_valid_counterparty { + ($counterparty_txid: expr, $htlc_output: expr) => { + if let Some(txid) = $counterparty_txid { + for &(ref pending_htlc, ref pending_source) in self.counterparty_claimable_outpoints.get(&txid).unwrap() { if pending_htlc.payment_hash == $htlc_output.payment_hash && pending_htlc.amount_msat == $htlc_output.amount_msat { if let &Some(ref source) = pending_source { - log_claim!("revoked remote commitment tx", false, pending_htlc, true); + log_claim!("revoked counterparty commitment tx", false, pending_htlc, true); payment_data = Some(((**source).clone(), $htlc_output.payment_hash)); break; } @@ -2036,25 +2139,25 @@ impl ChannelMonitor { } macro_rules! scan_commitment { - ($htlcs: expr, $tx_info: expr, $local_tx: expr) => { + ($htlcs: expr, $tx_info: expr, $holder_tx: expr) => { for (ref htlc_output, source_option) in $htlcs { if Some(input.previous_output.vout) == htlc_output.transaction_output_index { if let Some(ref source) = source_option { - log_claim!($tx_info, $local_tx, htlc_output, true); + log_claim!($tx_info, $holder_tx, htlc_output, true); // We have a resolution of an HTLC either from one of our latest - // local commitment transactions or an unrevoked remote commitment + // holder commitment transactions or an unrevoked counterparty commitment // transaction. This implies we either learned a preimage, the HTLC // has timed out, or we screwed up. In any case, we should now // resolve the source HTLC with the original sender. payment_data = Some(((*source).clone(), htlc_output.payment_hash)); - } else if !$local_tx { - check_htlc_valid_remote!(self.current_remote_commitment_txid, htlc_output); + } else if !$holder_tx { + check_htlc_valid_counterparty!(self.current_counterparty_commitment_txid, htlc_output); if payment_data.is_none() { - check_htlc_valid_remote!(self.prev_remote_commitment_txid, htlc_output); + check_htlc_valid_counterparty!(self.prev_counterparty_commitment_txid, htlc_output); } } if payment_data.is_none() { - log_claim!($tx_info, $local_tx, htlc_output, false); + log_claim!($tx_info, $holder_tx, htlc_output, false); continue 'outer_loop; } } @@ -2062,19 +2165,19 @@ impl ChannelMonitor { } } - if input.previous_output.txid == self.current_local_commitment_tx.txid { - scan_commitment!(self.current_local_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())), - "our latest local commitment tx", true); + if input.previous_output.txid == self.current_holder_commitment_tx.txid { + scan_commitment!(self.current_holder_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())), + "our latest holder commitment tx", true); } - if let Some(ref prev_local_signed_commitment_tx) = self.prev_local_signed_commitment_tx { - if input.previous_output.txid == prev_local_signed_commitment_tx.txid { - scan_commitment!(prev_local_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())), - "our previous local commitment tx", true); + if let Some(ref prev_holder_signed_commitment_tx) = self.prev_holder_signed_commitment_tx { + if input.previous_output.txid == prev_holder_signed_commitment_tx.txid { + scan_commitment!(prev_holder_signed_commitment_tx.htlc_outputs.iter().map(|&(ref a, _, ref b)| (a, b.as_ref())), + "our previous holder commitment tx", true); } } - if let Some(ref htlc_outputs) = self.remote_claimable_outpoints.get(&input.previous_output.txid) { + if let Some(ref htlc_outputs) = self.counterparty_claimable_outpoints.get(&input.previous_output.txid) { scan_commitment!(htlc_outputs.iter().map(|&(ref a, ref b)| (a, (b.as_ref().clone()).map(|boxed| &**boxed))), - "remote commitment tx", false); + "counterparty commitment tx", false); } // Check that scan_commitment, above, decided there is some source worth relaying an @@ -2082,22 +2185,26 @@ impl ChannelMonitor { if let Some((source, payment_hash)) = payment_data { let mut payment_preimage = PaymentPreimage([0; 32]); if accepted_preimage_claim { - if !self.pending_htlcs_updated.iter().any(|update| update.source == source) { + if !self.pending_monitor_events.iter().any( + |update| if let &MonitorEvent::HTLCEvent(ref upd) = update { upd.source == source } else { false }) { payment_preimage.0.copy_from_slice(&input.witness[3]); - self.pending_htlcs_updated.push(HTLCUpdate { + self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate { source, payment_preimage: Some(payment_preimage), payment_hash - }); + })); } } else if offered_preimage_claim { - if !self.pending_htlcs_updated.iter().any(|update| update.source == source) { + if !self.pending_monitor_events.iter().any( + |update| if let &MonitorEvent::HTLCEvent(ref upd) = update { + upd.source == source + } else { false }) { payment_preimage.0.copy_from_slice(&input.witness[1]); - self.pending_htlcs_updated.push(HTLCUpdate { + self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate { source, payment_preimage: Some(payment_preimage), payment_hash - }); + })); } } else { log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height{})", log_bytes!(payment_hash.0), height + ANTI_REORG_DELAY - 1); @@ -2127,33 +2234,48 @@ impl ChannelMonitor { fn is_paying_spendable_output(&mut self, tx: &Transaction, height: u32, logger: &L) where L::Target: Logger { let mut spendable_output = None; for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us + if i > ::std::u16::MAX as usize { + // While it is possible that an output exists on chain which is greater than the + // 2^16th output in a given transaction, this is only possible if the output is not + // in a lightning transaction and was instead placed there by some third party who + // wishes to give us money for no reason. + // Namely, any lightning transactions which we pre-sign will never have anywhere + // near 2^16 outputs both because such transactions must have ~2^16 outputs who's + // scripts are not longer than one byte in length and because they are inherently + // non-standard due to their size. + // Thus, it is completely safe to ignore such outputs, and while it may result in + // us ignoring non-lightning fund to us, that is only possible if someone fills + // nearly a full block with garbage just to hit this case. + continue; + } if outp.script_pubkey == self.destination_script { spendable_output = Some(SpendableOutputDescriptor::StaticOutput { - outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, + outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, output: outp.clone(), }); break; - } else if let Some(ref broadcasted_local_revokable_script) = self.broadcasted_local_revokable_script { - if broadcasted_local_revokable_script.0 == outp.script_pubkey { + } else if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script { + if broadcasted_holder_revokable_script.0 == outp.script_pubkey { spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH { - outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, - key: broadcasted_local_revokable_script.1, - witness_script: broadcasted_local_revokable_script.2.clone(), - to_self_delay: self.their_to_self_delay, + outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, + per_commitment_point: broadcasted_holder_revokable_script.1, + to_self_delay: self.on_holder_tx_csv, output: outp.clone(), + key_derivation_params: self.keys.key_derivation_params(), + revocation_pubkey: broadcasted_holder_revokable_script.2.clone(), }); break; } - } else if self.remote_payment_script == outp.script_pubkey { - spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WPKH { - outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, - key: self.keys.payment_key().clone(), + } else if self.counterparty_payment_script == outp.script_pubkey { + spendable_output = Some(SpendableOutputDescriptor::StaticOutputCounterpartyPayment { + outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, output: outp.clone(), + key_derivation_params: self.keys.key_derivation_params(), }); break; } else if outp.script_pubkey == self.shutdown_script { spendable_output = Some(SpendableOutputDescriptor::StaticOutput { - outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 }, + outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, output: outp.clone(), }); } @@ -2196,17 +2318,17 @@ impl Readable for (BlockHash, ChannelMonitor let commitment_transaction_number_obscure_factor = ::read(reader)?.0; let destination_script = Readable::read(reader)?; - let broadcasted_local_revokable_script = match ::read(reader)? { + let broadcasted_holder_revokable_script = match ::read(reader)? { 0 => { let revokable_address = Readable::read(reader)?; - let local_delayedkey = Readable::read(reader)?; + let per_commitment_point = Readable::read(reader)?; let revokable_script = Readable::read(reader)?; - Some((revokable_address, local_delayedkey, revokable_script)) + Some((revokable_address, per_commitment_point, revokable_script)) }, 1 => { None }, _ => return Err(DecodeError::InvalidValue), }; - let remote_payment_script = Readable::read(reader)?; + let counterparty_payment_script = Readable::read(reader)?; let shutdown_script = Readable::read(reader)?; let keys = Readable::read(reader)?; @@ -2217,11 +2339,10 @@ impl Readable for (BlockHash, ChannelMonitor index: Readable::read(reader)?, }; let funding_info = (outpoint, Readable::read(reader)?); - let current_remote_commitment_txid = Readable::read(reader)?; - let prev_remote_commitment_txid = Readable::read(reader)?; + let current_counterparty_commitment_txid = Readable::read(reader)?; + let prev_counterparty_commitment_txid = Readable::read(reader)?; - let their_htlc_base_key = Readable::read(reader)?; - let their_delayed_payment_base_key = Readable::read(reader)?; + let counterparty_tx_cache = Readable::read(reader)?; let funding_redeemscript = Readable::read(reader)?; let channel_value_satoshis = Readable::read(reader)?; @@ -2240,8 +2361,7 @@ impl Readable for (BlockHash, ChannelMonitor } }; - let our_to_self_delay: u16 = Readable::read(reader)?; - let their_to_self_delay: u16 = Readable::read(reader)?; + let on_holder_tx_csv: u16 = Readable::read(reader)?; let commitment_secrets = Readable::read(reader)?; @@ -2261,23 +2381,23 @@ impl Readable for (BlockHash, ChannelMonitor } } - let remote_claimable_outpoints_len: u64 = Readable::read(reader)?; - let mut remote_claimable_outpoints = HashMap::with_capacity(cmp::min(remote_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64)); - for _ in 0..remote_claimable_outpoints_len { + let counterparty_claimable_outpoints_len: u64 = Readable::read(reader)?; + let mut counterparty_claimable_outpoints = HashMap::with_capacity(cmp::min(counterparty_claimable_outpoints_len as usize, MAX_ALLOC_SIZE / 64)); + for _ in 0..counterparty_claimable_outpoints_len { let txid: Txid = Readable::read(reader)?; let htlcs_count: u64 = Readable::read(reader)?; let mut htlcs = Vec::with_capacity(cmp::min(htlcs_count as usize, MAX_ALLOC_SIZE / 32)); for _ in 0..htlcs_count { htlcs.push((read_htlc_in_commitment!(), as Readable>::read(reader)?.map(|o: HTLCSource| Box::new(o)))); } - if let Some(_) = remote_claimable_outpoints.insert(txid, htlcs) { + if let Some(_) = counterparty_claimable_outpoints.insert(txid, htlcs) { return Err(DecodeError::InvalidValue); } } - let remote_commitment_txn_on_chain_len: u64 = Readable::read(reader)?; - let mut remote_commitment_txn_on_chain = HashMap::with_capacity(cmp::min(remote_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32)); - for _ in 0..remote_commitment_txn_on_chain_len { + let counterparty_commitment_txn_on_chain_len: u64 = Readable::read(reader)?; + let mut counterparty_commitment_txn_on_chain = HashMap::with_capacity(cmp::min(counterparty_commitment_txn_on_chain_len as usize, MAX_ALLOC_SIZE / 32)); + for _ in 0..counterparty_commitment_txn_on_chain_len { let txid: Txid = Readable::read(reader)?; let commitment_number = ::read(reader)?.0; let outputs_count = ::read(reader)?; @@ -2285,22 +2405,22 @@ impl Readable for (BlockHash, ChannelMonitor for _ in 0..outputs_count { outputs.push(Readable::read(reader)?); } - if let Some(_) = remote_commitment_txn_on_chain.insert(txid, (commitment_number, outputs)) { + if let Some(_) = counterparty_commitment_txn_on_chain.insert(txid, (commitment_number, outputs)) { return Err(DecodeError::InvalidValue); } } - let remote_hash_commitment_number_len: u64 = Readable::read(reader)?; - let mut remote_hash_commitment_number = HashMap::with_capacity(cmp::min(remote_hash_commitment_number_len as usize, MAX_ALLOC_SIZE / 32)); - for _ in 0..remote_hash_commitment_number_len { + let counterparty_hash_commitment_number_len: u64 = Readable::read(reader)?; + let mut counterparty_hash_commitment_number = HashMap::with_capacity(cmp::min(counterparty_hash_commitment_number_len as usize, MAX_ALLOC_SIZE / 32)); + for _ in 0..counterparty_hash_commitment_number_len { let payment_hash: PaymentHash = Readable::read(reader)?; let commitment_number = ::read(reader)?.0; - if let Some(_) = remote_hash_commitment_number.insert(payment_hash, commitment_number) { + if let Some(_) = counterparty_hash_commitment_number.insert(payment_hash, commitment_number) { return Err(DecodeError::InvalidValue); } } - macro_rules! read_local_tx { + macro_rules! read_holder_tx { () => { { let txid = Readable::read(reader)?; @@ -2309,7 +2429,7 @@ impl Readable for (BlockHash, ChannelMonitor let b_htlc_key = Readable::read(reader)?; let delayed_payment_key = Readable::read(reader)?; let per_commitment_point = Readable::read(reader)?; - let feerate_per_kw: u64 = Readable::read(reader)?; + let feerate_per_kw: u32 = Readable::read(reader)?; let htlcs_len: u64 = Readable::read(reader)?; let mut htlcs = Vec::with_capacity(cmp::min(htlcs_len as usize, MAX_ALLOC_SIZE / 128)); @@ -2323,7 +2443,7 @@ impl Readable for (BlockHash, ChannelMonitor htlcs.push((htlc, sigs, Readable::read(reader)?)); } - LocalSignedTx { + HolderSignedTx { txid, revocation_key, a_htlc_key, b_htlc_key, delayed_payment_key, per_commitment_point, feerate_per_kw, htlc_outputs: htlcs @@ -2332,17 +2452,17 @@ impl Readable for (BlockHash, ChannelMonitor } } - let prev_local_signed_commitment_tx = match ::read(reader)? { + let prev_holder_signed_commitment_tx = match ::read(reader)? { 0 => None, 1 => { - Some(read_local_tx!()) + Some(read_holder_tx!()) }, _ => return Err(DecodeError::InvalidValue), }; - let current_local_commitment_tx = read_local_tx!(); + let current_holder_commitment_tx = read_holder_tx!(); - let current_remote_commitment_number = ::read(reader)?.0; - let current_local_commitment_number = ::read(reader)?.0; + let current_counterparty_commitment_number = ::read(reader)?.0; + let current_holder_commitment_number = ::read(reader)?.0; let payment_preimages_len: u64 = Readable::read(reader)?; let mut payment_preimages = HashMap::with_capacity(cmp::min(payment_preimages_len as usize, MAX_ALLOC_SIZE / 32)); @@ -2354,14 +2474,19 @@ impl Readable for (BlockHash, ChannelMonitor } } - let pending_htlcs_updated_len: u64 = Readable::read(reader)?; - let mut pending_htlcs_updated = Vec::with_capacity(cmp::min(pending_htlcs_updated_len as usize, MAX_ALLOC_SIZE / (32 + 8*3))); - for _ in 0..pending_htlcs_updated_len { - pending_htlcs_updated.push(Readable::read(reader)?); + let pending_monitor_events_len: u64 = Readable::read(reader)?; + let mut pending_monitor_events = Vec::with_capacity(cmp::min(pending_monitor_events_len as usize, MAX_ALLOC_SIZE / (32 + 8*3))); + for _ in 0..pending_monitor_events_len { + let ev = match ::read(reader)? { + 0 => MonitorEvent::HTLCEvent(Readable::read(reader)?), + 1 => MonitorEvent::CommitmentTxBroadcasted(funding_info.0), + _ => return Err(DecodeError::InvalidValue) + }; + pending_monitor_events.push(ev); } let pending_events_len: u64 = Readable::read(reader)?; - let mut pending_events = Vec::with_capacity(cmp::min(pending_events_len as usize, MAX_ALLOC_SIZE / mem::size_of::())); + let mut pending_events = Vec::with_capacity(cmp::min(pending_events_len as usize, MAX_ALLOC_SIZE / mem::size_of::())); for _ in 0..pending_events_len { if let Some(event) = MaybeReadable::read(reader)? { pending_events.push(event); @@ -2414,43 +2539,41 @@ impl Readable for (BlockHash, ChannelMonitor let onchain_tx_handler = Readable::read(reader)?; let lockdown_from_offchain = Readable::read(reader)?; - let local_tx_signed = Readable::read(reader)?; + let holder_tx_signed = Readable::read(reader)?; Ok((last_block_hash.clone(), ChannelMonitor { latest_update_id, commitment_transaction_number_obscure_factor, destination_script, - broadcasted_local_revokable_script, - remote_payment_script, + broadcasted_holder_revokable_script, + counterparty_payment_script, shutdown_script, keys, funding_info, - current_remote_commitment_txid, - prev_remote_commitment_txid, + current_counterparty_commitment_txid, + prev_counterparty_commitment_txid, - their_htlc_base_key, - their_delayed_payment_base_key, + counterparty_tx_cache, funding_redeemscript, channel_value_satoshis, their_cur_revocation_points, - our_to_self_delay, - their_to_self_delay, + on_holder_tx_csv, commitment_secrets, - remote_claimable_outpoints, - remote_commitment_txn_on_chain, - remote_hash_commitment_number, + counterparty_claimable_outpoints, + counterparty_commitment_txn_on_chain, + counterparty_hash_commitment_number, - prev_local_signed_commitment_tx, - current_local_commitment_tx, - current_remote_commitment_number, - current_local_commitment_number, + prev_holder_signed_commitment_tx, + current_holder_commitment_tx, + current_counterparty_commitment_number, + current_holder_commitment_number, payment_preimages, - pending_htlcs_updated, + pending_monitor_events, pending_events, onchain_events_waiting_threshold_conf, @@ -2459,7 +2582,7 @@ impl Readable for (BlockHash, ChannelMonitor onchain_tx_handler, lockdown_from_offchain, - local_tx_signed, + holder_tx_signed, last_block_hash, secp_ctx: Secp256k1::new(), @@ -2484,11 +2607,10 @@ mod tests { use ln::channelmonitor::ChannelMonitor; use ln::onchaintx::{OnchainTxHandler, InputDescriptors}; use ln::chan_utils; - use ln::chan_utils::{HTLCOutputInCommitment, LocalCommitmentTransaction}; + use ln::chan_utils::{HTLCOutputInCommitment, HolderCommitmentTransaction}; use util::test_utils::TestLogger; use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; - use rand::{thread_rng,Rng}; use std::sync::Arc; use chain::keysinterface::InMemoryChannelKeys; @@ -2502,10 +2624,8 @@ mod tests { let mut preimages = Vec::new(); { - let mut rng = thread_rng(); - for _ in 0..20 { - let mut preimage = PaymentPreimage([0; 32]); - rng.fill_bytes(&mut preimage.0[..]); + for i in 0..20 { + let preimage = PaymentPreimage([i; 32]); let hash = PaymentHash(Sha256::hash(&preimage.0[..]).into_inner()); preimages.push((preimage, hash)); } @@ -2528,7 +2648,7 @@ mod tests { } } } - macro_rules! preimages_to_local_htlcs { + macro_rules! preimages_to_holder_htlcs { ($preimages_slice: expr) => { { let mut inp = preimages_slice_to_htlc_outputs!($preimages_slice); @@ -2555,22 +2675,23 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], 0, + (0, 0) ); - // Prune with one old state and a local commitment tx holding a few overlaps with the + // Prune with one old state and a holder commitment tx holding a few overlaps with the // old state. let mut monitor = ChannelMonitor::new(keys, &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(), (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[44; 32]).unwrap()), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap()), - 10, Script::new(), 46, 0, LocalCommitmentTransaction::dummy()); + 10, Script::new(), 46, 0, HolderCommitmentTransaction::dummy()); - monitor.provide_latest_local_commitment_tx_info(LocalCommitmentTransaction::dummy(), preimages_to_local_htlcs!(preimages[0..10])).unwrap(); - monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger); - monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key, &logger); - monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key, &logger); - monitor.provide_latest_remote_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key, &logger); + monitor.provide_latest_holder_commitment_tx_info(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..10])).unwrap(); + monitor.provide_latest_counterparty_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[5..15]), 281474976710655, dummy_key, &logger); + monitor.provide_latest_counterparty_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[15..20]), 281474976710654, dummy_key, &logger); + monitor.provide_latest_counterparty_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[17..20]), 281474976710653, dummy_key, &logger); + monitor.provide_latest_counterparty_commitment_tx_info(&dummy_tx, preimages_slice_to_htlc_outputs!(preimages[18..20]), 281474976710652, dummy_key, &logger); for &(ref preimage, ref hash) in preimages.iter() { monitor.provide_payment_preimage(hash, preimage); } @@ -2590,9 +2711,9 @@ mod tests { test_preimages_exist!(&preimages[0..10], monitor); test_preimages_exist!(&preimages[17..20], monitor); - // Now update local commitment tx info, pruning only element 18 as we still care about the + // Now update holder commitment tx info, pruning only element 18 as we still care about the // previous commitment tx's preimages too - monitor.provide_latest_local_commitment_tx_info(LocalCommitmentTransaction::dummy(), preimages_to_local_htlcs!(preimages[0..5])).unwrap(); + monitor.provide_latest_holder_commitment_tx_info(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..5])).unwrap(); secret[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap()); monitor.provide_secret(281474976710653, secret.clone()).unwrap(); assert_eq!(monitor.payment_preimages.len(), 12); @@ -2600,7 +2721,7 @@ mod tests { test_preimages_exist!(&preimages[18..20], monitor); // But if we do it again, we'll prune 5-10 - monitor.provide_latest_local_commitment_tx_info(LocalCommitmentTransaction::dummy(), preimages_to_local_htlcs!(preimages[0..3])).unwrap(); + monitor.provide_latest_holder_commitment_tx_info(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..3])).unwrap(); secret[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap()); monitor.provide_secret(281474976710652, secret.clone()).unwrap(); assert_eq!(monitor.payment_preimages.len(), 5); @@ -2618,40 +2739,40 @@ mod tests { let mut sum_actual_sigs = 0; macro_rules! sign_input { - ($sighash_parts: expr, $input: expr, $idx: expr, $amount: expr, $input_type: expr, $sum_actual_sigs: expr) => { + ($sighash_parts: expr, $idx: expr, $amount: expr, $input_type: expr, $sum_actual_sigs: expr) => { let htlc = HTLCOutputInCommitment { offered: if *$input_type == InputDescriptors::RevokedOfferedHTLC || *$input_type == InputDescriptors::OfferedHTLC { true } else { false }, amount_msat: 0, cltv_expiry: 2 << 16, payment_hash: PaymentHash([1; 32]), - transaction_output_index: Some($idx), + transaction_output_index: Some($idx as u32), }; let redeem_script = if *$input_type == InputDescriptors::RevokedOutput { chan_utils::get_revokeable_redeemscript(&pubkey, 256, &pubkey) } else { chan_utils::get_htlc_redeemscript_with_explicit_keys(&htlc, &pubkey, &pubkey, &pubkey) }; - let sighash = hash_to_message!(&$sighash_parts.sighash_all(&$input, &redeem_script, $amount)[..]); + let sighash = hash_to_message!(&$sighash_parts.signature_hash($idx, &redeem_script, $amount, SigHashType::All)[..]); let sig = secp_ctx.sign(&sighash, &privkey); - $input.witness.push(sig.serialize_der().to_vec()); - $input.witness[0].push(SigHashType::All as u8); - sum_actual_sigs += $input.witness[0].len(); + $sighash_parts.access_witness($idx).push(sig.serialize_der().to_vec()); + $sighash_parts.access_witness($idx)[0].push(SigHashType::All as u8); + sum_actual_sigs += $sighash_parts.access_witness($idx)[0].len(); if *$input_type == InputDescriptors::RevokedOutput { - $input.witness.push(vec!(1)); + $sighash_parts.access_witness($idx).push(vec!(1)); } else if *$input_type == InputDescriptors::RevokedOfferedHTLC || *$input_type == InputDescriptors::RevokedReceivedHTLC { - $input.witness.push(pubkey.clone().serialize().to_vec()); + $sighash_parts.access_witness($idx).push(pubkey.clone().serialize().to_vec()); } else if *$input_type == InputDescriptors::ReceivedHTLC { - $input.witness.push(vec![0]); + $sighash_parts.access_witness($idx).push(vec![0]); } else { - $input.witness.push(PaymentPreimage([1; 32]).0.to_vec()); + $sighash_parts.access_witness($idx).push(PaymentPreimage([1; 32]).0.to_vec()); } - $input.witness.push(redeem_script.into_bytes()); - println!("witness[0] {}", $input.witness[0].len()); - println!("witness[1] {}", $input.witness[1].len()); - println!("witness[2] {}", $input.witness[2].len()); + $sighash_parts.access_witness($idx).push(redeem_script.into_bytes()); + println!("witness[0] {}", $sighash_parts.access_witness($idx)[0].len()); + println!("witness[1] {}", $sighash_parts.access_witness($idx)[1].len()); + println!("witness[2] {}", $sighash_parts.access_witness($idx)[2].len()); } } let script_pubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(); let txid = Txid::from_hex("56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d").unwrap(); - // Justice tx with 1 to_local, 2 revoked offered HTLCs, 1 revoked received HTLCs + // Justice tx with 1 to_holder, 2 revoked offered HTLCs, 1 revoked received HTLCs let mut claim_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() }; for i in 0..4 { claim_tx.input.push(TxIn { @@ -2669,10 +2790,12 @@ mod tests { value: 0, }); let base_weight = claim_tx.get_weight(); - let sighash_parts = bip143::SighashComponents::new(&claim_tx); let inputs_des = vec![InputDescriptors::RevokedOutput, InputDescriptors::RevokedOfferedHTLC, InputDescriptors::RevokedOfferedHTLC, InputDescriptors::RevokedReceivedHTLC]; - for (idx, inp) in claim_tx.input.iter_mut().zip(inputs_des.iter()).enumerate() { - sign_input!(sighash_parts, inp.0, idx as u32, 0, inp.1, sum_actual_sigs); + { + let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + for (idx, inp) in inputs_des.iter().enumerate() { + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs); + } } assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs)); @@ -2691,10 +2814,12 @@ mod tests { }); } let base_weight = claim_tx.get_weight(); - let sighash_parts = bip143::SighashComponents::new(&claim_tx); let inputs_des = vec![InputDescriptors::OfferedHTLC, InputDescriptors::ReceivedHTLC, InputDescriptors::ReceivedHTLC, InputDescriptors::ReceivedHTLC]; - for (idx, inp) in claim_tx.input.iter_mut().zip(inputs_des.iter()).enumerate() { - sign_input!(sighash_parts, inp.0, idx as u32, 0, inp.1, sum_actual_sigs); + { + let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + for (idx, inp) in inputs_des.iter().enumerate() { + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs); + } } assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs)); @@ -2711,10 +2836,12 @@ mod tests { witness: Vec::new(), }); let base_weight = claim_tx.get_weight(); - let sighash_parts = bip143::SighashComponents::new(&claim_tx); let inputs_des = vec![InputDescriptors::RevokedOutput]; - for (idx, inp) in claim_tx.input.iter_mut().zip(inputs_des.iter()).enumerate() { - sign_input!(sighash_parts, inp.0, idx as u32, 0, inp.1, sum_actual_sigs); + { + let mut sighash_parts = bip143::SigHashCache::new(&mut claim_tx); + for (idx, inp) in inputs_des.iter().enumerate() { + sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs); + } } assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_des.len() - sum_actual_sigs)); }