X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fchain%2Fchannelmonitor.rs;h=24dfc57b6265c638cabff1715cb83c818d764827;hb=836985a5e5e8036d5dea47797ef6fba498616e67;hp=b46a2df13eea8d8c462e1df72dd6dca9fac2b45f;hpb=0b20cf62e78dc6cfbe34772af0f9f7481ec68ef5;p=rust-lightning diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index b46a2df1..24dfc57b 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -19,10 +19,8 @@ //! 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`]: ../trait.Watch.html -use bitcoin::blockdata::block::BlockHeader; +use bitcoin::blockdata::block::{Block, BlockHeader}; use bitcoin::blockdata::transaction::{TxOut,Transaction}; use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint; use bitcoin::blockdata::script::{Script, Builder}; @@ -41,9 +39,11 @@ use ln::chan_utils; use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction}; use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash}; use ln::onchaintx::{OnchainTxHandler, InputDescriptors}; +use chain; use chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use chain::transaction::{OutPoint, TransactionData}; -use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys, KeysInterface}; +use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface}; +use chain::Filter; use util::logger::Logger; use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48}; use util::byte_utils; @@ -51,8 +51,9 @@ use util::events::Event; use std::collections::{HashMap, HashSet, hash_map}; use std::{cmp, mem}; -use std::ops::Deref; use std::io::Error; +use std::ops::Deref; +use std::sync::Mutex; /// An update generated by the underlying Channel itself which contains some new information the /// ChannelMonitor should be made aware of. @@ -72,8 +73,6 @@ pub struct ChannelMonitorUpdate { /// The only instance where update_id values are not strictly increasing is the case where we /// allow post-force-close updates with a special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. See /// its docs for more details. - /// - /// [`CLOSED_CHANNEL_UPDATE_ID`]: constant.CLOSED_CHANNEL_UPDATE_ID.html pub update_id: u64, } @@ -174,7 +173,7 @@ pub enum ChannelMonitorUpdateErr { /// means you tried to update a monitor for a different channel or the ChannelMonitorUpdate was /// corrupted. /// Contains a developer-readable error message. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct MonitorUpdateError(pub &'static str); /// An event to be processed by the ChannelManager. @@ -190,8 +189,6 @@ pub enum MonitorEvent { /// 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`]: ../trait.Watch.html #[derive(Clone, PartialEq)] pub struct HTLCUpdate { pub(crate) payment_hash: PaymentHash, @@ -618,12 +615,19 @@ impl Readable for ChannelMonitorUpdateStep { /// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events /// gotten are fully handled before re-serializing the new state. /// -/// Note that the deserializer is only implemented for (Sha256dHash, ChannelMonitor), which +/// Note that the deserializer is only implemented for (BlockHash, ChannelMonitor), which /// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along /// 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 struct ChannelMonitor { +pub struct ChannelMonitor { + #[cfg(test)] + pub(crate) inner: Mutex>, + #[cfg(not(test))] + inner: Mutex>, +} + +pub(crate) struct ChannelMonitorImpl { latest_update_id: u64, commitment_transaction_number_obscure_factor: u64, @@ -632,7 +636,7 @@ pub struct ChannelMonitor { counterparty_payment_script: Script, shutdown_script: Script, - key_derivation_params: (u64, u64), + channel_keys_id: [u8; 32], holder_revocation_basepoint: PublicKey, funding_info: (OutPoint, Script), current_counterparty_commitment_txid: Option, @@ -691,9 +695,9 @@ pub struct ChannelMonitor { outputs_to_watch: HashMap>, #[cfg(test)] - pub onchain_tx_handler: OnchainTxHandler, + pub onchain_tx_handler: OnchainTxHandler, #[cfg(not(test))] - onchain_tx_handler: OnchainTxHandler, + 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 holder commitment transaction @@ -721,14 +725,25 @@ pub struct ChannelMonitor { #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] /// Used only in testing and fuzztarget to check serialization roundtrips don't change the /// underlying object -impl PartialEq for ChannelMonitor { +impl PartialEq for ChannelMonitor { + fn eq(&self, other: &Self) -> bool { + let inner = self.inner.lock().unwrap(); + let other = other.inner.lock().unwrap(); + inner.eq(&other) + } +} + +#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))] +/// Used only in testing and fuzztarget to check serialization roundtrips don't change the +/// underlying object +impl PartialEq for ChannelMonitorImpl { fn eq(&self, other: &Self) -> bool { 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_holder_revokable_script != other.broadcasted_holder_revokable_script || self.counterparty_payment_script != other.counterparty_payment_script || - self.key_derivation_params != other.key_derivation_params || + self.channel_keys_id != other.channel_keys_id || self.holder_revocation_basepoint != other.holder_revocation_basepoint || self.funding_info != other.funding_info || self.current_counterparty_commitment_txid != other.current_counterparty_commitment_txid || @@ -761,13 +776,19 @@ impl PartialEq for ChannelMonitor { } } -impl Writeable for ChannelMonitor { +impl Writeable for ChannelMonitor { fn write(&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])?; writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?; + self.inner.lock().unwrap().write(writer) + } +} + +impl Writeable for ChannelMonitorImpl { + fn write(&self, writer: &mut W) -> Result<(), Error> { self.latest_update_id.write(writer)?; // Set in initial Channel-object creation, so should always be set by now: @@ -786,7 +807,7 @@ impl Writeable for ChannelMonitor { self.counterparty_payment_script.write(writer)?; self.shutdown_script.write(writer)?; - self.key_derivation_params.write(writer)?; + self.channel_keys_id.write(writer)?; self.holder_revocation_basepoint.write(writer)?; writer.write_all(&self.funding_info.0.txid[..])?; writer.write_all(&byte_utils::be16_to_array(self.funding_info.0.index))?; @@ -948,13 +969,14 @@ impl Writeable for ChannelMonitor { } } -impl ChannelMonitor { - pub(crate) fn new(keys: ChanSigner, shutdown_pubkey: &PublicKey, +impl ChannelMonitor { + pub(crate) fn new(secp_ctx: Secp256k1, keys: Signer, shutdown_pubkey: &PublicKey, on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script), channel_parameters: &ChannelTransactionParameters, funding_redeemscript: Script, channel_value_satoshis: u64, commitment_transaction_number_obscure_factor: u64, - initial_holder_commitment_tx: HolderCommitmentTransaction) -> ChannelMonitor { + initial_holder_commitment_tx: HolderCommitmentTransaction, + last_block_hash: BlockHash) -> ChannelMonitor { assert!(commitment_transaction_number_obscure_factor <= (1 << 48)); let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize()); @@ -967,11 +989,9 @@ impl ChannelMonitor { let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint; let counterparty_tx_cache = CounterpartyCommitmentTransaction { counterparty_delayed_payment_base_key, counterparty_htlc_base_key, on_counterparty_tx_csv, per_htlc: HashMap::new() }; - let key_derivation_params = keys.key_derivation_params(); + let channel_keys_id = keys.channel_keys_id(); let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint; - let secp_ctx = Secp256k1::new(); - // block for Rust 1.34 compat let (holder_commitment_tx, current_holder_commitment_number) = { let trusted_tx = initial_holder_commitment_tx.trust(); @@ -992,60 +1012,273 @@ impl ChannelMonitor { }; let onchain_tx_handler = - OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone(), initial_holder_commitment_tx); + OnchainTxHandler::new(destination_script.clone(), keys, + channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone()); let mut outputs_to_watch = HashMap::new(); outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]); ChannelMonitor { - latest_update_id: 0, - commitment_transaction_number_obscure_factor, + inner: Mutex::new(ChannelMonitorImpl { + latest_update_id: 0, + commitment_transaction_number_obscure_factor, + + destination_script: destination_script.clone(), + broadcasted_holder_revokable_script: None, + counterparty_payment_script, + shutdown_script, - destination_script: destination_script.clone(), - broadcasted_holder_revokable_script: None, - counterparty_payment_script, - shutdown_script, + channel_keys_id, + holder_revocation_basepoint, + funding_info, + current_counterparty_commitment_txid: None, + prev_counterparty_commitment_txid: None, - key_derivation_params, - holder_revocation_basepoint, - funding_info, - current_counterparty_commitment_txid: None, - prev_counterparty_commitment_txid: None, + counterparty_tx_cache, + funding_redeemscript, + channel_value_satoshis, + their_cur_revocation_points: None, - counterparty_tx_cache, - funding_redeemscript, - channel_value_satoshis, - their_cur_revocation_points: None, + on_holder_tx_csv: counterparty_channel_parameters.selected_contest_delay, - on_holder_tx_csv: counterparty_channel_parameters.selected_contest_delay, + commitment_secrets: CounterpartyCommitmentSecrets::new(), + counterparty_claimable_outpoints: HashMap::new(), + counterparty_commitment_txn_on_chain: HashMap::new(), + counterparty_hash_commitment_number: HashMap::new(), + + prev_holder_signed_commitment_tx: None, + current_holder_commitment_tx: holder_commitment_tx, + current_counterparty_commitment_number: 1 << 48, + current_holder_commitment_number, + + payment_preimages: HashMap::new(), + pending_monitor_events: Vec::new(), + pending_events: Vec::new(), + + onchain_events_waiting_threshold_conf: HashMap::new(), + outputs_to_watch, + + onchain_tx_handler, + + lockdown_from_offchain: false, + holder_tx_signed: false, + + last_block_hash, + secp_ctx, + }), + } + } + + #[cfg(test)] + fn provide_secret(&self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> { + self.inner.lock().unwrap().provide_secret(idx, secret) + } + + /// 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(crate) fn provide_latest_counterparty_commitment_tx( + &self, + txid: Txid, + htlc_outputs: Vec<(HTLCOutputInCommitment, Option>)>, + commitment_number: u64, + their_revocation_point: PublicKey, + logger: &L, + ) where L::Target: Logger { + self.inner.lock().unwrap().provide_latest_counterparty_commitment_tx( + txid, htlc_outputs, commitment_number, their_revocation_point, logger) + } + + #[cfg(test)] + fn provide_latest_holder_commitment_tx( + &self, + holder_commitment_tx: HolderCommitmentTransaction, + htlc_outputs: Vec<(HTLCOutputInCommitment, Option, Option)>, + ) -> Result<(), MonitorUpdateError> { + self.inner.lock().unwrap().provide_latest_holder_commitment_tx( + holder_commitment_tx, htlc_outputs) + } - commitment_secrets: CounterpartyCommitmentSecrets::new(), - counterparty_claimable_outpoints: HashMap::new(), - counterparty_commitment_txn_on_chain: HashMap::new(), - counterparty_hash_commitment_number: HashMap::new(), + #[cfg(test)] + pub(crate) fn provide_payment_preimage( + &self, + payment_hash: &PaymentHash, + payment_preimage: &PaymentPreimage, + broadcaster: &B, + fee_estimator: &F, + logger: &L, + ) where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + { + self.inner.lock().unwrap().provide_payment_preimage( + payment_hash, payment_preimage, broadcaster, fee_estimator, logger) + } - prev_holder_signed_commitment_tx: None, - current_holder_commitment_tx: holder_commitment_tx, - current_counterparty_commitment_number: 1 << 48, - current_holder_commitment_number, + pub(crate) fn broadcast_latest_holder_commitment_txn( + &self, + broadcaster: &B, + logger: &L, + ) where + B::Target: BroadcasterInterface, + L::Target: Logger, + { + self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger) + } - payment_preimages: HashMap::new(), - pending_monitor_events: Vec::new(), - pending_events: Vec::new(), + /// Updates a ChannelMonitor on the basis of some new information provided by the Channel + /// itself. + /// + /// panics if the given update is not the next update by update_id. + pub fn update_monitor( + &self, + updates: &ChannelMonitorUpdate, + broadcaster: &B, + fee_estimator: &F, + logger: &L, + ) -> Result<(), MonitorUpdateError> + where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + { + self.inner.lock().unwrap().update_monitor(updates, broadcaster, fee_estimator, logger) + } - onchain_events_waiting_threshold_conf: HashMap::new(), - outputs_to_watch, + /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this + /// ChannelMonitor. + pub fn get_latest_update_id(&self) -> u64 { + self.inner.lock().unwrap().get_latest_update_id() + } - onchain_tx_handler, + /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for. + pub fn get_funding_txo(&self) -> (OutPoint, Script) { + self.inner.lock().unwrap().get_funding_txo().clone() + } - lockdown_from_offchain: false, - holder_tx_signed: false, + /// 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(). + pub fn get_outputs_to_watch(&self) -> Vec<(Txid, Vec<(u32, Script)>)> { + self.inner.lock().unwrap().get_outputs_to_watch() + .iter().map(|(txid, outputs)| (*txid, outputs.clone())).collect() + } - last_block_hash: Default::default(), - secp_ctx, + /// Loads the funding txo and outputs to watch into the given `chain::Filter` by repeatedly + /// calling `chain::Filter::register_output` and `chain::Filter::register_tx` until all outputs + /// have been registered. + pub fn load_outputs_to_watch(&self, filter: &F) where F::Target: chain::Filter { + let lock = self.inner.lock().unwrap(); + filter.register_tx(&lock.get_funding_txo().0.txid, &lock.get_funding_txo().1); + for (txid, outputs) in lock.get_outputs_to_watch().iter() { + for (index, script_pubkey) in outputs.iter() { + assert!(*index <= u16::max_value() as u32); + filter.register_output(&OutPoint { txid: *txid, index: *index as u16 }, script_pubkey); + } } } + /// Get the list of HTLCs who's status has been updated on chain. This should be called by + /// ChannelManager via [`chain::Watch::release_pending_monitor_events`]. + pub fn get_and_clear_pending_monitor_events(&self) -> Vec { + self.inner.lock().unwrap().get_and_clear_pending_monitor_events() + } + + /// Gets the list of pending events which were generated by previous actions, clearing the list + /// in the process. + /// + /// 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(&self) -> Vec { + self.inner.lock().unwrap().get_and_clear_pending_events() + } + + pub(crate) fn get_min_seen_secret(&self) -> u64 { + self.inner.lock().unwrap().get_min_seen_secret() + } + + pub(crate) fn get_cur_counterparty_commitment_number(&self) -> u64 { + self.inner.lock().unwrap().get_cur_counterparty_commitment_number() + } + + pub(crate) fn get_cur_holder_commitment_number(&self) -> u64 { + self.inner.lock().unwrap().get_cur_holder_commitment_number() + } + + /// 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_holder_commitment_txn(&self, logger: &L) -> Vec + where L::Target: Logger { + self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger) + } + + /// 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(any(test, feature = "unsafe_revoked_tx_signing"))] + pub fn unsafe_get_latest_holder_commitment_txn(&self, logger: &L) -> Vec + where L::Target: Logger { + self.inner.lock().unwrap().unsafe_get_latest_holder_commitment_txn(logger) + } + + /// 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 new outputs to watch from `txdata`; after called, these are also included in + /// [`get_outputs_to_watch`]. + /// + /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch + pub fn block_connected( + &self, + header: &BlockHeader, + txdata: &TransactionData, + height: u32, + broadcaster: B, + fee_estimator: F, + logger: L, + ) -> Vec<(Txid, Vec<(u32, TxOut)>)> + where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + { + self.inner.lock().unwrap().block_connected( + header, txdata, height, broadcaster, fee_estimator, logger) + } + + /// Determines if the disconnected block contained any transactions of interest and updates + /// appropriately. + pub fn block_disconnected( + &self, + header: &BlockHeader, + height: u32, + broadcaster: B, + fee_estimator: F, + logger: L, + ) where + B::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, + { + self.inner.lock().unwrap().block_disconnected( + header, height, broadcaster, fee_estimator, logger) + } +} + +impl ChannelMonitorImpl { /// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither /// 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). @@ -1097,10 +1330,6 @@ impl ChannelMonitor { Ok(()) } - /// 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(crate) fn provide_latest_counterparty_commitment_tx(&mut self, txid: Txid, 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. @@ -1177,7 +1406,7 @@ impl ChannelMonitor { /// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all /// commitment_tx_infos which contain the payment hash have been revoked. - pub(crate) fn provide_payment_preimage(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L) + fn provide_payment_preimage(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L) where B::Target: BroadcasterInterface, F::Target: FeeEstimator, L::Target: Logger, @@ -1230,10 +1459,6 @@ impl ChannelMonitor { 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 - /// itself. - /// - /// panics if the given update is not the next update by update_id. pub fn update_monitor(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), MonitorUpdateError> where B::Target: BroadcasterInterface, F::Target: FeeEstimator, @@ -1286,21 +1511,14 @@ impl ChannelMonitor { Ok(()) } - /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this - /// ChannelMonitor. pub fn get_latest_update_id(&self) -> u64 { self.latest_update_id } - /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for. 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> { // If we've detected a counterparty commitment tx on chain, we must include it in the set // of outputs to watch for spends of, otherwise we're likely to lose user funds. Because @@ -1311,22 +1529,12 @@ impl ChannelMonitor { &self.outputs_to_watch } - /// Get the list of HTLCs who's status has been updated on chain. This should be called by - /// ChannelManager via [`chain::Watch::release_pending_monitor_events`]. - /// - /// [`chain::Watch::release_pending_monitor_events`]: ../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_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 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 { let mut ret = Vec::new(); mem::swap(&mut ret, &mut self.pending_events); @@ -1714,15 +1922,6 @@ impl ChannelMonitor { (claim_requests, (commitment_txid, watch_outputs)) } - /// 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_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; @@ -1748,11 +1947,8 @@ impl ChannelMonitor { return res; } - /// 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(any(test,feature = "unsafe_revoked_tx_signing"))] - pub fn unsafe_get_latest_holder_commitment_txn(&mut self, logger: &L) -> Vec where L::Target: Logger { + 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!"); let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript); let txid = commitment_tx.txid(); @@ -1774,17 +1970,6 @@ impl ChannelMonitor { return res } - /// 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 new outputs to watch from `txdata`; after called, these are also included in - /// [`get_outputs_to_watch`]. - /// - /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch pub fn block_connected(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L)-> Vec<(Txid, Vec<(u32, TxOut)>)> where B::Target: BroadcasterInterface, F::Target: FeeEstimator, @@ -1906,15 +2091,12 @@ impl ChannelMonitor { watch_outputs } - /// 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); + log_trace!(logger, "Block {} at height {} disconnected", header.block_hash(), height); if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) { //We may discard: @@ -1924,7 +2106,7 @@ impl ChannelMonitor { self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger); - self.last_block_hash = block_hash; + self.last_block_hash = header.prev_blockhash; } /// Filters a block's `txdata` for transactions spending watched outputs or for any child @@ -2201,22 +2383,24 @@ impl ChannelMonitor { break; } 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 { + spendable_output = Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor { 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.key_derivation_params, revocation_pubkey: broadcasted_holder_revokable_script.2.clone(), - }); + channel_keys_id: self.channel_keys_id, + channel_value_satoshis: self.channel_value_satoshis, + })); break; } } else if self.counterparty_payment_script == outp.script_pubkey { - spendable_output = Some(SpendableOutputDescriptor::StaticOutputCounterpartyPayment { + spendable_output = Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor { outpoint: OutPoint { txid: tx.txid(), index: i as u16 }, output: outp.clone(), - key_derivation_params: self.key_derivation_params, - }); + channel_keys_id: self.channel_keys_id, + channel_value_satoshis: self.channel_value_satoshis, + })); break; } else if outp.script_pubkey == self.shutdown_script { spendable_output = Some(SpendableOutputDescriptor::StaticOutput { @@ -2251,19 +2435,16 @@ impl ChannelMonitor { /// transaction and losing money. This is a risk because previous channel states /// are toxic, so it's important that whatever channel state is persisted is /// kept up-to-date. -pub trait Persist: Send + Sync { +pub trait Persist: Send + Sync { /// Persist a new channel's data. The data can be stored any way you want, but /// the identifier provided by Rust-Lightning is the channel's outpoint (and /// it is up to you to maintain a correct mapping between the outpoint and the /// stored channel data). Note that you **must** persist every new monitor to /// disk. See the `Persist` trait documentation for more details. /// - /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`, + /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`, /// and [`ChannelMonitorUpdateErr`] for requirements when returning errors. - /// - /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk - /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html - fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; + fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; /// Update one channel's data. The provided `ChannelMonitor` has already /// applied the given update. @@ -2284,21 +2465,32 @@ pub trait Persist: Send + Sync { /// them in batches. The size of each monitor grows `O(number of state updates)` /// whereas updates are small and `O(1)`. /// - /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`, + /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`, /// [`ChannelMonitorUpdate::write`] for writing out an update, and /// [`ChannelMonitorUpdateErr`] for requirements when returning errors. - /// - /// [`ChannelMonitor::update_monitor`]: struct.ChannelMonitor.html#impl-1 - /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk - /// [`ChannelMonitorUpdate::write`]: struct.ChannelMonitorUpdate.html#method.write - /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html - fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; + fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; +} + +impl chain::Listen for (ChannelMonitor, T, F, L) +where + T::Target: BroadcasterInterface, + F::Target: FeeEstimator, + L::Target: Logger, +{ + fn block_connected(&self, block: &Block, height: u32) { + let txdata: Vec<_> = block.txdata.iter().enumerate().collect(); + self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3); + } + + fn block_disconnected(&self, header: &BlockHeader, height: u32) { + self.0.block_disconnected(header, height, &*self.1, &*self.2, &*self.3); + } } const MAX_ALLOC_SIZE: usize = 64*1024; -impl<'a, ChanSigner: ChannelKeys, K: KeysInterface> ReadableArgs<&'a K> - for (BlockHash, ChannelMonitor) { +impl<'a, Signer: Sign, K: KeysInterface> ReadableArgs<&'a K> + for (BlockHash, ChannelMonitor) { fn read(reader: &mut R, keys_manager: &'a K) -> Result { macro_rules! unwrap_obj { ($key: expr) => { @@ -2332,7 +2524,7 @@ impl<'a, ChanSigner: ChannelKeys, K: KeysInterface> let counterparty_payment_script = Readable::read(reader)?; let shutdown_script = Readable::read(reader)?; - let key_derivation_params = Readable::read(reader)?; + let channel_keys_id = Readable::read(reader)?; let holder_revocation_basepoint = Readable::read(reader)?; // Technically this can fail and serialize fail a round-trip, but only for serialization of // barely-init'd ChannelMonitors that we can't do anything with. @@ -2538,58 +2730,64 @@ impl<'a, ChanSigner: ChannelKeys, K: KeysInterface> let lockdown_from_offchain = Readable::read(reader)?; let holder_tx_signed = Readable::read(reader)?; + let mut secp_ctx = Secp256k1::new(); + secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes()); + Ok((last_block_hash.clone(), ChannelMonitor { - latest_update_id, - commitment_transaction_number_obscure_factor, + inner: Mutex::new(ChannelMonitorImpl { + latest_update_id, + commitment_transaction_number_obscure_factor, - destination_script, - broadcasted_holder_revokable_script, - counterparty_payment_script, - shutdown_script, + destination_script, + broadcasted_holder_revokable_script, + counterparty_payment_script, + shutdown_script, - key_derivation_params, - holder_revocation_basepoint, - funding_info, - current_counterparty_commitment_txid, - prev_counterparty_commitment_txid, + channel_keys_id, + holder_revocation_basepoint, + funding_info, + current_counterparty_commitment_txid, + prev_counterparty_commitment_txid, - counterparty_tx_cache, - funding_redeemscript, - channel_value_satoshis, - their_cur_revocation_points, + counterparty_tx_cache, + funding_redeemscript, + channel_value_satoshis, + their_cur_revocation_points, - on_holder_tx_csv, + on_holder_tx_csv, - commitment_secrets, - counterparty_claimable_outpoints, - counterparty_commitment_txn_on_chain, - counterparty_hash_commitment_number, + commitment_secrets, + counterparty_claimable_outpoints, + counterparty_commitment_txn_on_chain, + counterparty_hash_commitment_number, - prev_holder_signed_commitment_tx, - current_holder_commitment_tx, - current_counterparty_commitment_number, - current_holder_commitment_number, + prev_holder_signed_commitment_tx, + current_holder_commitment_tx, + current_counterparty_commitment_number, + current_holder_commitment_number, - payment_preimages, - pending_monitor_events, - pending_events, + payment_preimages, + pending_monitor_events, + pending_events, - onchain_events_waiting_threshold_conf, - outputs_to_watch, + onchain_events_waiting_threshold_conf, + outputs_to_watch, - onchain_tx_handler, + onchain_tx_handler, - lockdown_from_offchain, - holder_tx_signed, + lockdown_from_offchain, + holder_tx_signed, - last_block_hash, - secp_ctx: Secp256k1::new(), + last_block_hash, + secp_ctx, + }), })) } } #[cfg(test)] mod tests { + use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::script::{Script, Builder}; use bitcoin::blockdata::opcodes; use bitcoin::blockdata::transaction::{Transaction, TxIn, TxOut, SigHashType}; @@ -2599,6 +2797,7 @@ mod tests { use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::hex::FromHex; use bitcoin::hash_types::Txid; + use bitcoin::network::constants::Network; use hex; use chain::channelmonitor::ChannelMonitor; use chain::transaction::OutPoint; @@ -2610,7 +2809,7 @@ mod tests { use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use bitcoin::secp256k1::Secp256k1; use std::sync::{Arc, Mutex}; - use chain::keysinterface::InMemoryChannelKeys; + use chain::keysinterface::InMemorySigner; #[test] fn test_prune_preimages() { @@ -2661,12 +2860,12 @@ mod tests { macro_rules! test_preimages_exist { ($preimages_slice: expr, $monitor: expr) => { for preimage in $preimages_slice { - assert!($monitor.payment_preimages.contains_key(&preimage.1)); + assert!($monitor.inner.lock().unwrap().payment_preimages.contains_key(&preimage.1)); } } } - let keys = InMemoryChannelKeys::new( + let keys = InMemorySigner::new( &secp_ctx, SecretKey::from_slice(&[41; 32]).unwrap(), SecretKey::from_slice(&[41; 32]).unwrap(), @@ -2675,7 +2874,7 @@ mod tests { SecretKey::from_slice(&[41; 32]).unwrap(), [41; 32], 0, - (0, 0) + [0; 32] ); let counterparty_pubkeys = ChannelPublicKeys { @@ -2698,12 +2897,13 @@ mod tests { }; // 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()), - &channel_parameters, - Script::new(), 46, 0, - HolderCommitmentTransaction::dummy()); + let last_block_hash = genesis_block(Network::Testnet).block_hash(); + let monitor = ChannelMonitor::new(Secp256k1::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()), + &channel_parameters, + Script::new(), 46, 0, + HolderCommitmentTransaction::dummy(), last_block_hash); monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..10])).unwrap(); let dummy_txid = dummy_tx.txid(); @@ -2719,14 +2919,14 @@ mod tests { let mut secret = [0; 32]; secret[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap()); monitor.provide_secret(281474976710655, secret.clone()).unwrap(); - assert_eq!(monitor.payment_preimages.len(), 15); + assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 15); test_preimages_exist!(&preimages[0..10], monitor); test_preimages_exist!(&preimages[15..20], monitor); // Now provide a further secret, pruning preimages 15-17 secret[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap()); monitor.provide_secret(281474976710654, secret.clone()).unwrap(); - assert_eq!(monitor.payment_preimages.len(), 13); + assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 13); test_preimages_exist!(&preimages[0..10], monitor); test_preimages_exist!(&preimages[17..20], monitor); @@ -2735,7 +2935,7 @@ mod tests { monitor.provide_latest_holder_commitment_tx(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); + assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 12); test_preimages_exist!(&preimages[0..10], monitor); test_preimages_exist!(&preimages[18..20], monitor); @@ -2743,7 +2943,7 @@ mod tests { monitor.provide_latest_holder_commitment_tx(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); + assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 5); test_preimages_exist!(&preimages[0..5], monitor); } @@ -2816,7 +3016,7 @@ mod tests { 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)); + assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs)); // Claim tx with 1 offered HTLCs, 3 received HTLCs claim_tx.input.clear(); @@ -2840,7 +3040,7 @@ mod tests { 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)); + assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs)); // Justice tx with 1 revoked HTLC-Success tx output claim_tx.input.clear(); @@ -2862,7 +3062,7 @@ mod tests { 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)); + assert_eq!(base_weight + OnchainTxHandler::::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_des.len() - sum_actual_sigs)); } // Further testing is done in the ChannelManager integration tests.