X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmonitor.rs;h=bbcbe75c67bf43bc78c0069e734c11ecff3ee447;hb=ab7a0a54318cdd55bedc3a02604af200b16e2e2c;hp=373f811e9ae4ea8ec77f104edff12fef1c0bca08;hpb=f930fc1886dbfdc388be79579ef02e788e2478f5;p=rust-lightning diff --git a/lightning/src/ln/channelmonitor.rs b/lightning/src/ln/channelmonitor.rs index 373f811e..bbcbe75c 100644 --- a/lightning/src/ln/channelmonitor.rs +++ b/lightning/src/ln/channelmonitor.rs @@ -131,9 +131,9 @@ pub enum ChannelMonitorUpdateErr { } /// General Err type for ChannelMonitor actions. Generally, this implies that the data provided is -/// inconsistent with the ChannelMonitor being called. eg for ChannelMonitor::insert_combine this -/// means you tried to merge two monitors for different channels or for a channel which was -/// restored from a backup and then generated new commitment updates. +/// inconsistent with the ChannelMonitor being called. eg for ChannelMonitor::update_monitor this +/// means you tried to update a monitor for a different channel or the ChannelMonitorUpdate was +/// corrupted. /// Contains a human-readable error message. #[derive(Debug)] pub struct MonitorUpdateError(pub &'static str); @@ -150,7 +150,7 @@ impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); /// Simple trait indicating ability to track a set of ChannelMonitors and multiplex events between /// them. Generally should be implemented by keeping a local SimpleManyChannelMonitor and passing -/// events to it, while also taking any add_update_monitor events and passing them to some remote +/// events to it, while also taking any add/update_monitor events and passing them to some remote /// server(s). /// /// Note that any updates to a channel's monitor *must* be applied to each instance of the @@ -164,7 +164,7 @@ impl_writeable!(HTLCUpdate, 0, { payment_hash, payment_preimage, source }); /// BlockNotifier and call the BlockNotifier's `block_(dis)connected` methods, which will notify /// all registered listeners in one go. pub trait ManyChannelMonitor: Send + Sync { - /// Adds or updates a monitor for the given `funding_txo`. + /// 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 @@ -176,7 +176,7 @@ pub trait ManyChannelMonitor: Send + Sync { /// /// 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_update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; + fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr>; /// Updates a monitor for the given `funding_txo`. /// @@ -279,14 +279,11 @@ impl) -> Result<(), MonitorUpdateError> { + pub fn add_monitor_by_key(&self, key: Key, monitor: ChannelMonitor) -> Result<(), MonitorUpdateError> { let mut monitors = self.monitors.lock().unwrap(); - match monitors.get_mut(&key) { - Some(orig_monitor) => { - log_trace!(self, "Updating Channel Monitor for channel {}", log_funding_info!(monitor.key_storage)); - return orig_monitor.insert_combine(monitor); - }, - None => {} + 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, }; match monitor.key_storage { Storage::Local { ref funding_info, .. } => { @@ -310,7 +307,7 @@ impl ManyChannelMonitor for SimpleManyChannelMonitor where T::Target: BroadcasterInterface { - fn add_update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { - match self.add_update_monitor_by_key(funding_txo, monitor) { + fn add_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor) -> Result<(), ChannelMonitorUpdateErr> { + match self.add_monitor_by_key(funding_txo, monitor) { Ok(_) => Ok(()), Err(_) => Err(ChannelMonitorUpdateErr::PermanentFailure), } @@ -393,7 +390,6 @@ pub(crate) const LATENCY_GRACE_PERIOD_BLOCKS: u32 = 3; /// keeping bumping another claim tx to solve the outpoint. pub(crate) const ANTI_REORG_DELAY: u32 = 6; -#[derive(Clone)] enum Storage { Local { keys: ChanSigner, @@ -788,7 +784,6 @@ impl Readable for ChannelMonitorUpdateStep { /// /// You MUST ensure that no ChannelMonitors for a given channel anywhere contain out-of-date /// information and are actively monitoring the chain. -#[derive(Clone)] pub struct ChannelMonitor { latest_update_id: u64, commitment_transaction_number_obscure_factor: u64, @@ -879,7 +874,7 @@ pub struct ChannelMonitor { // 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 insert_combine to ensure any local user copies keep + // (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: Sha256dHash, @@ -1215,31 +1210,43 @@ impl ChannelMonitor { } impl ChannelMonitor { - pub(super) fn new(keys: ChanSigner, funding_key: &SecretKey, revocation_base_key: &SecretKey, delayed_payment_base_key: &SecretKey, htlc_base_key: &SecretKey, payment_base_key: &SecretKey, shutdown_pubkey: &PublicKey, our_to_self_delay: u16, destination_script: Script, logger: Arc) -> 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, + commitment_transaction_number_obscure_factor: u64, + logger: Arc) -> ChannelMonitor { + + assert!(commitment_transaction_number_obscure_factor <= (1 << 48)); + let funding_key = keys.funding_key().clone(); + let revocation_base_key = keys.revocation_base_key().clone(); + let htlc_base_key = keys.htlc_base_key().clone(); + let delayed_payment_base_key = keys.delayed_payment_base_key().clone(); + let payment_base_key = keys.payment_base_key().clone(); ChannelMonitor { latest_update_id: 0, - commitment_transaction_number_obscure_factor: 0, + commitment_transaction_number_obscure_factor, key_storage: Storage::Local { keys, - funding_key: funding_key.clone(), - revocation_base_key: revocation_base_key.clone(), - htlc_base_key: htlc_base_key.clone(), - delayed_payment_base_key: delayed_payment_base_key.clone(), - payment_base_key: payment_base_key.clone(), + funding_key, + revocation_base_key, + htlc_base_key, + delayed_payment_base_key, + payment_base_key, shutdown_pubkey: shutdown_pubkey.clone(), - funding_info: None, + funding_info: Some(funding_info), current_remote_commitment_txid: None, prev_remote_commitment_txid: None, }, - their_htlc_base_key: None, - their_delayed_payment_base_key: None, - funding_redeemscript: None, - channel_value_satoshis: None, + their_htlc_base_key: Some(their_htlc_base_key.clone()), + their_delayed_payment_base_key: Some(their_delayed_payment_base_key.clone()), + funding_redeemscript: Some(funding_redeemscript), + channel_value_satoshis: Some(channel_value_satoshis), their_cur_revocation_points: None, our_to_self_delay: our_to_self_delay, - their_to_self_delay: None, + their_to_self_delay: Some(their_to_self_delay), commitment_secrets: CounterpartyCommitmentSecrets::new(), remote_claimable_outpoints: HashMap::new(), @@ -1253,7 +1260,7 @@ impl ChannelMonitor { payment_preimages: HashMap::new(), pending_htlcs_updated: Vec::new(), - destination_script: destination_script, + destination_script: destination_script.clone(), to_remote_rescue: None, pending_claim_requests: HashMap::new(), @@ -1497,97 +1504,6 @@ impl ChannelMonitor { Ok(()) } - /// Combines this ChannelMonitor with the information contained in the other ChannelMonitor. - /// After a successful call this ChannelMonitor is up-to-date and is safe to use to monitor the - /// chain for new blocks/transactions. - pub fn insert_combine(&mut self, mut other: ChannelMonitor) -> Result<(), MonitorUpdateError> { - match self.key_storage { - Storage::Local { ref funding_info, .. } => { - if funding_info.is_none() { return Err(MonitorUpdateError("Try to combine a Local monitor without funding_info")); } - let our_funding_info = funding_info; - if let Storage::Local { ref funding_info, .. } = other.key_storage { - if funding_info.is_none() { return Err(MonitorUpdateError("Try to combine a Local monitor without funding_info")); } - // We should be able to compare the entire funding_txo, but in fuzztarget it's trivially - // easy to collide the funding_txo hash and have a different scriptPubKey. - if funding_info.as_ref().unwrap().0 != our_funding_info.as_ref().unwrap().0 { - return Err(MonitorUpdateError("Funding transaction outputs are not identical!")); - } - } else { - return Err(MonitorUpdateError("Try to combine a Local monitor with a Watchtower one !")); - } - }, - Storage::Watchtower { .. } => { - if let Storage::Watchtower { .. } = other.key_storage { - unimplemented!(); - } else { - return Err(MonitorUpdateError("Try to combine a Watchtower monitor with a Local one !")); - } - }, - } - let other_min_secret = other.get_min_seen_secret(); - let our_min_secret = self.get_min_seen_secret(); - if our_min_secret > other_min_secret { - self.provide_secret(other_min_secret, other.get_secret(other_min_secret).unwrap())?; - } - if let Some(ref local_tx) = self.current_local_signed_commitment_tx { - if let Some(ref other_local_tx) = other.current_local_signed_commitment_tx { - let our_commitment_number = 0xffffffffffff - ((((local_tx.tx.without_valid_witness().input[0].sequence as u64 & 0xffffff) << 3*8) | (local_tx.tx.without_valid_witness().lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor); - let other_commitment_number = 0xffffffffffff - ((((other_local_tx.tx.without_valid_witness().input[0].sequence as u64 & 0xffffff) << 3*8) | (other_local_tx.tx.without_valid_witness().lock_time as u64 & 0xffffff)) ^ other.commitment_transaction_number_obscure_factor); - if our_commitment_number >= other_commitment_number { - self.key_storage = other.key_storage; - } - } - } - // TODO: We should use current_remote_commitment_number and the commitment number out of - // local transactions to decide how to merge - if our_min_secret >= other_min_secret { - self.their_cur_revocation_points = other.their_cur_revocation_points; - for (txid, htlcs) in other.remote_claimable_outpoints.drain() { - self.remote_claimable_outpoints.insert(txid, htlcs); - } - if let Some(local_tx) = other.prev_local_signed_commitment_tx { - self.prev_local_signed_commitment_tx = Some(local_tx); - } - if let Some(local_tx) = other.current_local_signed_commitment_tx { - self.current_local_signed_commitment_tx = Some(local_tx); - } - self.payment_preimages = other.payment_preimages; - self.to_remote_rescue = other.to_remote_rescue; - } - - self.current_remote_commitment_number = cmp::min(self.current_remote_commitment_number, other.current_remote_commitment_number); - Ok(()) - } - - /// Allows this monitor to scan only for transactions which are applicable. Note that this is - /// optional, without it this monitor cannot be used in an SPV client, but you may wish to - /// avoid this on a monitor you wish to send to a watchtower as it provides slightly better - /// privacy. - /// It's the responsibility of the caller to register outpoint and script with passing the former - /// value as key to add_update_monitor. - pub(super) fn set_funding_info(&mut self, new_funding_info: (OutPoint, Script)) { - match self.key_storage { - Storage::Local { ref mut funding_info, .. } => { - *funding_info = Some(new_funding_info); - }, - Storage::Watchtower { .. } => { - panic!("Channel somehow ended up with its internal ChannelMonitor being in Watchtower mode?"); - } - } - } - - /// We log these base keys at channel opening to being able to rebuild redeemscript in case of leaked revoked commit tx - /// Panics if commitment_transaction_number_obscure_factor doesn't fit in 48 bits - pub(super) fn set_basic_channel_info(&mut self, their_htlc_base_key: &PublicKey, their_delayed_payment_base_key: &PublicKey, their_to_self_delay: u16, funding_redeemscript: Script, channel_value_satoshis: u64, commitment_transaction_number_obscure_factor: u64) { - self.their_htlc_base_key = Some(their_htlc_base_key.clone()); - self.their_delayed_payment_base_key = Some(their_delayed_payment_base_key.clone()); - self.their_to_self_delay = Some(their_to_self_delay); - self.funding_redeemscript = Some(funding_redeemscript); - self.channel_value_satoshis = Some(channel_value_satoshis); - assert!(commitment_transaction_number_obscure_factor < (1 << 48)); - self.commitment_transaction_number_obscure_factor = commitment_transaction_number_obscure_factor; - } - /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this /// ChannelMonitor. pub fn get_latest_update_id(&self) -> u64 { @@ -3571,6 +3487,7 @@ mod tests { use bitcoin_hashes::sha256d::Hash as Sha256dHash; use bitcoin_hashes::hex::FromHex; use hex; + use chain::transaction::OutPoint; use ln::channelmanager::{PaymentPreimage, PaymentHash}; use ln::channelmonitor::{ChannelMonitor, InputDescriptors}; use ln::chan_utils; @@ -3663,7 +3580,13 @@ mod tests { // Prune with one old state and a local commitment tx holding a few overlaps with the // old state. - let mut monitor = ChannelMonitor::new(keys, &SecretKey::from_slice(&[41; 32]).unwrap(), &SecretKey::from_slice(&[42; 32]).unwrap(), &SecretKey::from_slice(&[43; 32]).unwrap(), &SecretKey::from_slice(&[44; 32]).unwrap(), &SecretKey::from_slice(&[44; 32]).unwrap(), &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[45; 32]).unwrap()), 0, Script::new(), logger.clone()); + let mut monitor = ChannelMonitor::new(keys, + &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(), + (OutPoint { txid: Sha256dHash::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()), + 0, Script::new(), 46, 0, logger.clone()); + monitor.their_to_self_delay = Some(10); monitor.provide_latest_local_commitment_tx_info(LocalCommitmentTransaction::dummy(), dummy_keys!(), 0, preimages_to_local_htlcs!(preimages[0..10])).unwrap();