diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index bb290deba9c..99fa15fcf53 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -29,7 +29,7 @@ use bitcoin::hash_types::{BlockHash, Txid}; use crate::chain; use crate::chain::chaininterface::{BroadcasterInterface, FeeEstimator}; use crate::chain::channelmonitor::{ - Balance, ChannelMonitor, ChannelMonitorUpdate, MonitorEvent, TransactionOutputs, + write_util, Balance, ChannelMonitor, ChannelMonitorUpdate, MonitorEvent, TransactionOutputs, WithChannelMonitor, }; use crate::chain::transaction::{OutPoint, TransactionData}; @@ -37,7 +37,9 @@ use crate::chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput}; use crate::events::{self, Event, EventHandler, ReplayEvent}; use crate::ln::channel_state::ChannelDetails; use crate::ln::msgs::{self, BaseMessageHandler, Init, MessageSendEvent}; -use crate::ln::our_peer_storage::DecryptedOurPeerStorage; +use crate::ln::our_peer_storage::{ + DecryptedOurPeerStorage, PeerStorageMonitorHolder, PeerStorageMonitorHolderList, +}; use crate::ln::types::ChannelId; use crate::prelude::*; use crate::sign::ecdsa::EcdsaChannelSigner; @@ -47,6 +49,7 @@ use crate::types::features::{InitFeatures, NodeFeatures}; use crate::util::errors::APIError; use crate::util::logger::{Logger, WithContext}; use crate::util::persist::MonitorName; +use crate::util::ser::{VecWriter, Writeable}; use crate::util::wakers::{Future, Notifier}; use bitcoin::secp256k1::PublicKey; use core::ops::Deref; @@ -810,10 +813,36 @@ where } fn send_peer_storage(&self, their_node_id: PublicKey) { - // TODO: Serialize `ChannelMonitor`s inside `our_peer_storage`. - let random_bytes = self.entropy_source.get_secure_random_bytes(); - let serialised_channels = Vec::new(); + + // TODO(aditya): Choose n random channels so that peer storage does not exceed 64k. + let monitors = self.monitors.read().unwrap(); + let mut monitors_list = PeerStorageMonitorHolderList { monitors: Vec::new() }; + + for (chan_id, mon) in monitors.iter() { + let mut ser_chan = VecWriter(Vec::new()); + let min_seen_secret = mon.monitor.get_min_seen_secret(); + let counterparty_node_id = mon.monitor.get_counterparty_node_id(); + + match write_util(&mon.monitor.inner.lock().unwrap(), true, &mut ser_chan) { + Ok(_) => { + let peer_storage_monitor = PeerStorageMonitorHolder { + channel_id: *chan_id, + min_seen_secret, + counterparty_node_id, + monitor_bytes: ser_chan.0, + }; + + monitors_list.monitors.push(peer_storage_monitor); + }, + Err(_) => { + panic!("Can not write monitor for {}", mon.monitor.channel_id()) + }, + } + } + + let mut serialised_channels = Vec::new(); + monitors_list.write(&mut serialised_channels).unwrap(); let our_peer_storage = DecryptedOurPeerStorage::new(serialised_channels); let cipher = our_peer_storage.encrypt(&self.our_peerstorage_encryption_key, &random_bytes); diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 5a4a94b1641..6cdcb3e4daf 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1369,210 +1369,223 @@ impl Writeable for ChannelMonitor { } } -// These are also used for ChannelMonitorUpdate, above. -const SERIALIZATION_VERSION: u8 = 1; -const MIN_SERIALIZATION_VERSION: u8 = 1; - -impl Writeable for ChannelMonitorImpl { - #[rustfmt::skip] - fn write(&self, writer: &mut W) -> Result<(), Error> { - write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); - - self.latest_update_id.write(writer)?; +/// Utility function for writing [`ChannelMonitor`] to prevent code duplication in [`ChainMonitor`] while sending Peer Storage. +/// +/// NOTE: `is_stub` is true only when we are using this to serialise for Peer Storage. +/// +/// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor +#[rustfmt::skip] +pub(crate) fn write_util(channel_monitor: &ChannelMonitorImpl, is_stub: bool, writer: &mut W) -> Result<(), Error> { + write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); + + channel_monitor.latest_update_id.write(writer)?; + + // Set in initial Channel-object creation, so should always be set by now: + U48(channel_monitor.commitment_transaction_number_obscure_factor).write(writer)?; + + channel_monitor.destination_script.write(writer)?; + if let Some(ref broadcasted_holder_revokable_script) = channel_monitor.broadcasted_holder_revokable_script { + writer.write_all(&[0; 1])?; + 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])?; + } + + channel_monitor.counterparty_payment_script.write(writer)?; + match &channel_monitor.shutdown_script { + Some(script) => script.write(writer)?, + None => ScriptBuf::new().write(writer)?, + } + + channel_monitor.channel_keys_id.write(writer)?; + channel_monitor.holder_revocation_basepoint.write(writer)?; + let funding_outpoint = channel_monitor.get_funding_txo(); + writer.write_all(&funding_outpoint.txid[..])?; + writer.write_all(&funding_outpoint.index.to_be_bytes())?; + channel_monitor.funding.script_pubkey.write(writer)?; + channel_monitor.funding.current_counterparty_commitment_txid.write(writer)?; + channel_monitor.funding.prev_counterparty_commitment_txid.write(writer)?; + + channel_monitor.counterparty_commitment_params.write(writer)?; + channel_monitor.funding.redeem_script.write(writer)?; + channel_monitor.funding.channel_parameters.channel_value_satoshis.write(writer)?; + + match channel_monitor.their_cur_per_commitment_points { + Some((idx, pubkey, second_option)) => { + writer.write_all(&byte_utils::be48_to_array(idx))?; + writer.write_all(&pubkey.serialize())?; + match second_option { + Some(second_pubkey) => { + writer.write_all(&second_pubkey.serialize())?; + }, + None => { + writer.write_all(&[0; 33])?; + }, + } + }, + None => { + writer.write_all(&byte_utils::be48_to_array(0))?; + }, + } - // Set in initial Channel-object creation, so should always be set by now: - U48(self.commitment_transaction_number_obscure_factor).write(writer)?; + writer.write_all(&channel_monitor.on_holder_tx_csv.to_be_bytes())?; - self.destination_script.write(writer)?; - if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script { - writer.write_all(&[0; 1])?; - 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])?; - } + channel_monitor.commitment_secrets.write(writer)?; - self.counterparty_payment_script.write(writer)?; - match &self.shutdown_script { - Some(script) => script.write(writer)?, - None => ScriptBuf::new().write(writer)?, + #[rustfmt::skip] + macro_rules! serialize_htlc_in_commitment { + ($htlc_output: expr) => { + writer.write_all(&[$htlc_output.offered as u8; 1])?; + writer.write_all(&$htlc_output.amount_msat.to_be_bytes())?; + writer.write_all(&$htlc_output.cltv_expiry.to_be_bytes())?; + writer.write_all(&$htlc_output.payment_hash.0[..])?; + $htlc_output.transaction_output_index.write(writer)?; } + } - self.channel_keys_id.write(writer)?; - self.holder_revocation_basepoint.write(writer)?; - let funding_outpoint = self.get_funding_txo(); - writer.write_all(&funding_outpoint.txid[..])?; - writer.write_all(&funding_outpoint.index.to_be_bytes())?; - self.funding.script_pubkey.write(writer)?; - self.funding.current_counterparty_commitment_txid.write(writer)?; - self.funding.prev_counterparty_commitment_txid.write(writer)?; - - self.counterparty_commitment_params.write(writer)?; - self.funding.redeem_script.write(writer)?; - self.funding.channel_parameters.channel_value_satoshis.write(writer)?; - - match self.their_cur_per_commitment_points { - Some((idx, pubkey, second_option)) => { - writer.write_all(&byte_utils::be48_to_array(idx))?; - writer.write_all(&pubkey.serialize())?; - match second_option { - Some(second_pubkey) => { - writer.write_all(&second_pubkey.serialize())?; - }, - None => { - writer.write_all(&[0; 33])?; - }, - } - }, - None => { - writer.write_all(&byte_utils::be48_to_array(0))?; - }, + writer.write_all(&(channel_monitor.funding.counterparty_claimable_outpoints.len() as u64).to_be_bytes())?; + for (ref txid, ref htlc_infos) in channel_monitor.funding.counterparty_claimable_outpoints.iter() { + writer.write_all(&txid[..])?; + writer.write_all(&(htlc_infos.len() as u64).to_be_bytes())?; + for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() { + debug_assert!(htlc_source.is_none() || Some(**txid) == channel_monitor.funding.current_counterparty_commitment_txid + || Some(**txid) == channel_monitor.funding.prev_counterparty_commitment_txid, + "HTLC Sources for all revoked commitment transactions should be none!"); + serialize_htlc_in_commitment!(htlc_output); + htlc_source.as_ref().map(|b| b.as_ref()).write(writer)?; } + } - writer.write_all(&self.on_holder_tx_csv.to_be_bytes())?; + writer.write_all(&(channel_monitor.counterparty_commitment_txn_on_chain.len() as u64).to_be_bytes())?; + for (ref txid, commitment_number) in channel_monitor.counterparty_commitment_txn_on_chain.iter() { + writer.write_all(&txid[..])?; + writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; + } - self.commitment_secrets.write(writer)?; + writer.write_all(&(channel_monitor.counterparty_hash_commitment_number.len() as u64).to_be_bytes())?; + for (ref payment_hash, commitment_number) in channel_monitor.counterparty_hash_commitment_number.iter() { + writer.write_all(&payment_hash.0[..])?; + writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; + } - #[rustfmt::skip] - macro_rules! serialize_htlc_in_commitment { - ($htlc_output: expr) => { - writer.write_all(&[$htlc_output.offered as u8; 1])?; - writer.write_all(&$htlc_output.amount_msat.to_be_bytes())?; - writer.write_all(&$htlc_output.cltv_expiry.to_be_bytes())?; - writer.write_all(&$htlc_output.payment_hash.0[..])?; - $htlc_output.transaction_output_index.write(writer)?; - } - } + if let Some(holder_commitment_tx) = &channel_monitor.funding.prev_holder_commitment_tx { + writer.write_all(&[1; 1])?; + write_legacy_holder_commitment_data( + writer, holder_commitment_tx, &channel_monitor.prev_holder_htlc_data.as_ref().unwrap(), + )?; + } else { + writer.write_all(&[0; 1])?; + } - writer.write_all(&(self.funding.counterparty_claimable_outpoints.len() as u64).to_be_bytes())?; - for (ref txid, ref htlc_infos) in self.funding.counterparty_claimable_outpoints.iter() { - writer.write_all(&txid[..])?; - writer.write_all(&(htlc_infos.len() as u64).to_be_bytes())?; - for &(ref htlc_output, ref htlc_source) in htlc_infos.iter() { - debug_assert!(htlc_source.is_none() || Some(**txid) == self.funding.current_counterparty_commitment_txid - || Some(**txid) == self.funding.prev_counterparty_commitment_txid, - "HTLC Sources for all revoked commitment transactions should be none!"); - serialize_htlc_in_commitment!(htlc_output); - htlc_source.as_ref().map(|b| b.as_ref()).write(writer)?; - } - } + write_legacy_holder_commitment_data( + writer, &channel_monitor.funding.current_holder_commitment_tx, &channel_monitor.current_holder_htlc_data, + )?; - writer.write_all(&(self.counterparty_commitment_txn_on_chain.len() as u64).to_be_bytes())?; - for (ref txid, commitment_number) in self.counterparty_commitment_txn_on_chain.iter() { - writer.write_all(&txid[..])?; - writer.write_all(&byte_utils::be48_to_array(*commitment_number))?; - } + writer.write_all(&byte_utils::be48_to_array(channel_monitor.current_counterparty_commitment_number))?; + writer.write_all(&byte_utils::be48_to_array(channel_monitor.current_holder_commitment_number))?; - writer.write_all(&(self.counterparty_hash_commitment_number.len() as u64).to_be_bytes())?; - 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))?; - } + writer.write_all(&(channel_monitor.payment_preimages.len() as u64).to_be_bytes())?; + for (payment_preimage, _) in channel_monitor.payment_preimages.values() { + writer.write_all(&payment_preimage.0[..])?; + } - if let Some(holder_commitment_tx) = &self.funding.prev_holder_commitment_tx { - writer.write_all(&[1; 1])?; - write_legacy_holder_commitment_data( - writer, holder_commitment_tx, &self.prev_holder_htlc_data.as_ref().unwrap(), - )?; - } else { - writer.write_all(&[0; 1])?; + writer.write_all(&(channel_monitor.pending_monitor_events.iter().filter(|ev| match ev { + MonitorEvent::HTLCEvent(_) => true, + MonitorEvent::HolderForceClosed(_) => true, + MonitorEvent::HolderForceClosedWithInfo { .. } => true, + _ => false, + }).count() as u64).to_be_bytes())?; + for event in channel_monitor.pending_monitor_events.iter() { + match event { + MonitorEvent::HTLCEvent(upd) => { + 0u8.write(writer)?; + upd.write(writer)?; + }, + MonitorEvent::HolderForceClosed(_) => 1u8.write(writer)?, + // `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. To keep + // backwards compatibility, we write a `HolderForceClosed` event along with the + // `HolderForceClosedWithInfo` event. This is deduplicated in the reader. + MonitorEvent::HolderForceClosedWithInfo { .. } => 1u8.write(writer)?, + _ => {}, // Covered in the TLV writes below } + } - write_legacy_holder_commitment_data( - writer, &self.funding.current_holder_commitment_tx, &self.current_holder_htlc_data, - )?; + writer.write_all(&(channel_monitor.pending_events.len() as u64).to_be_bytes())?; + for event in channel_monitor.pending_events.iter() { + event.write(writer)?; + } - 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))?; + channel_monitor.best_block.block_hash.write(writer)?; + writer.write_all(&channel_monitor.best_block.height.to_be_bytes())?; - writer.write_all(&(self.payment_preimages.len() as u64).to_be_bytes())?; - for (payment_preimage, _) in self.payment_preimages.values() { - writer.write_all(&payment_preimage.0[..])?; - } + writer.write_all(&(channel_monitor.onchain_events_awaiting_threshold_conf.len() as u64).to_be_bytes())?; + for ref entry in channel_monitor.onchain_events_awaiting_threshold_conf.iter() { + entry.write(writer)?; + } - writer.write_all(&(self.pending_monitor_events.iter().filter(|ev| match ev { - MonitorEvent::HTLCEvent(_) => true, - MonitorEvent::HolderForceClosed(_) => true, - MonitorEvent::HolderForceClosedWithInfo { .. } => true, - _ => false, - }).count() as u64).to_be_bytes())?; - for event in self.pending_monitor_events.iter() { - match event { - MonitorEvent::HTLCEvent(upd) => { - 0u8.write(writer)?; - upd.write(writer)?; - }, - MonitorEvent::HolderForceClosed(_) => 1u8.write(writer)?, - // `HolderForceClosedWithInfo` replaced `HolderForceClosed` in v0.0.122. To keep - // backwards compatibility, we write a `HolderForceClosed` event along with the - // `HolderForceClosedWithInfo` event. This is deduplicated in the reader. - MonitorEvent::HolderForceClosedWithInfo { .. } => 1u8.write(writer)?, - _ => {}, // Covered in the TLV writes below - } + (channel_monitor.outputs_to_watch.len() as u64).write(writer)?; + for (txid, idx_scripts) in channel_monitor.outputs_to_watch.iter() { + txid.write(writer)?; + (idx_scripts.len() as u64).write(writer)?; + for (idx, script) in idx_scripts.iter() { + idx.write(writer)?; + script.write(writer)?; } + } - writer.write_all(&(self.pending_events.len() as u64).to_be_bytes())?; - for event in self.pending_events.iter() { - event.write(writer)?; - } + if !is_stub { + channel_monitor.onchain_tx_handler.write(writer)?; + } - self.best_block.block_hash.write(writer)?; - writer.write_all(&self.best_block.height.to_be_bytes())?; + channel_monitor.lockdown_from_offchain.write(writer)?; + channel_monitor.holder_tx_signed.write(writer)?; - writer.write_all(&(self.onchain_events_awaiting_threshold_conf.len() as u64).to_be_bytes())?; - for ref entry in self.onchain_events_awaiting_threshold_conf.iter() { - entry.write(writer)?; + // If we have a `HolderForceClosedWithInfo` event, we need to write the `HolderForceClosed` for backwards compatibility. + let pending_monitor_events = match channel_monitor.pending_monitor_events.iter().find(|ev| match ev { + MonitorEvent::HolderForceClosedWithInfo { .. } => true, + _ => false, + }) { + Some(MonitorEvent::HolderForceClosedWithInfo { outpoint, .. }) => { + let mut pending_monitor_events = channel_monitor.pending_monitor_events.clone(); + pending_monitor_events.push(MonitorEvent::HolderForceClosed(*outpoint)); + pending_monitor_events } + _ => channel_monitor.pending_monitor_events.clone(), + }; - (self.outputs_to_watch.len() as u64).write(writer)?; - for (txid, idx_scripts) in self.outputs_to_watch.iter() { - txid.write(writer)?; - (idx_scripts.len() as u64).write(writer)?; - for (idx, script) in idx_scripts.iter() { - idx.write(writer)?; - script.write(writer)?; - } - } - self.onchain_tx_handler.write(writer)?; - - self.lockdown_from_offchain.write(writer)?; - self.holder_tx_signed.write(writer)?; - - // If we have a `HolderForceClosedWithInfo` event, we need to write the `HolderForceClosed` for backwards compatibility. - let pending_monitor_events = match self.pending_monitor_events.iter().find(|ev| match ev { - MonitorEvent::HolderForceClosedWithInfo { .. } => true, - _ => false, - }) { - Some(MonitorEvent::HolderForceClosedWithInfo { outpoint, .. }) => { - let mut pending_monitor_events = self.pending_monitor_events.clone(); - pending_monitor_events.push(MonitorEvent::HolderForceClosed(*outpoint)); - pending_monitor_events - } - _ => self.pending_monitor_events.clone(), - }; + write_tlv_fields!(writer, { + (1, channel_monitor.funding_spend_confirmed, option), + (3, channel_monitor.htlcs_resolved_on_chain, required_vec), + (5, pending_monitor_events, required_vec), + (7, channel_monitor.funding_spend_seen, required), + (9, channel_monitor.counterparty_node_id, required), + (11, channel_monitor.confirmed_commitment_tx_counterparty_output, option), + (13, channel_monitor.spendable_txids_confirmed, required_vec), + (15, channel_monitor.counterparty_fulfilled_htlcs, required), + (17, channel_monitor.initial_counterparty_commitment_info, option), + (19, channel_monitor.channel_id, required), + (21, channel_monitor.balances_empty_height, option), + (23, channel_monitor.holder_pays_commitment_tx_fee, option), + (25, channel_monitor.payment_preimages, required), + (27, channel_monitor.first_confirmed_funding_txo, required), + (29, channel_monitor.initial_counterparty_commitment_tx, option), + (31, channel_monitor.funding.channel_parameters, required), + (32, channel_monitor.pending_funding, optional_vec), + }); - write_tlv_fields!(writer, { - (1, self.funding_spend_confirmed, option), - (3, self.htlcs_resolved_on_chain, required_vec), - (5, pending_monitor_events, required_vec), - (7, self.funding_spend_seen, required), - (9, self.counterparty_node_id, required), - (11, self.confirmed_commitment_tx_counterparty_output, option), - (13, self.spendable_txids_confirmed, required_vec), - (15, self.counterparty_fulfilled_htlcs, required), - (17, self.initial_counterparty_commitment_info, option), - (19, self.channel_id, required), - (21, self.balances_empty_height, option), - (23, self.holder_pays_commitment_tx_fee, option), - (25, self.payment_preimages, required), - (27, self.first_confirmed_funding_txo, required), - (29, self.initial_counterparty_commitment_tx, option), - (31, self.funding.channel_parameters, required), - (32, self.pending_funding, optional_vec), - }); + Ok(()) +} - Ok(()) +// These are also used for ChannelMonitorUpdate, above. +const SERIALIZATION_VERSION: u8 = 1; +const MIN_SERIALIZATION_VERSION: u8 = 1; + +impl Writeable for ChannelMonitorImpl { + #[rustfmt::skip] + fn write(&self, writer: &mut W) -> Result<(), Error> { + write_util(self, false, writer) } } diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8a904a90e64..1205e726b44 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -58,6 +58,7 @@ use crate::events::{ use crate::events::{FundingInfo, PaidBolt12Invoice}; // Since this struct is returned in `list_channels` methods, expose it here in case users want to // construct one themselves. +use crate::io; use crate::ln::channel::PendingV2Channel; use crate::ln::channel::{ self, Channel, ChannelError, ChannelUpdateStatus, FundedChannel, InboundV1Channel, @@ -78,7 +79,7 @@ use crate::ln::onion_payment::{ }; use crate::ln::onion_utils::{self}; use crate::ln::onion_utils::{HTLCFailReason, LocalHTLCFailureReason}; -use crate::ln::our_peer_storage::EncryptedOurPeerStorage; +use crate::ln::our_peer_storage::{EncryptedOurPeerStorage, PeerStorageMonitorHolderList}; #[cfg(test)] use crate::ln::outbound_payment; use crate::ln::outbound_payment::{ @@ -174,7 +175,6 @@ use lightning_invoice::{ use alloc::collections::{btree_map, BTreeMap}; -use crate::io; use crate::io::Read; use crate::prelude::*; use crate::sync::{Arc, FairRwLock, LockHeldState, LockTestExt, Mutex, RwLock, RwLockReadGuard}; @@ -3014,6 +3014,7 @@ pub(super) const MAX_UNFUNDED_CHANNEL_PEERS: usize = 50; /// This constant defines the upper limit for the size of data /// that can be stored for a peer. It is set to 1024 bytes (1 kilobyte) /// to prevent excessive resource consumption. +#[cfg(not(test))] const MAX_PEER_STORAGE_SIZE: usize = 1024; /// The maximum number of peers which we do not have a (funded) channel with. Once we reach this @@ -8807,6 +8808,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ &self, peer_node_id: PublicKey, msg: msgs::PeerStorageRetrieval, ) -> Result<(), MsgHandleErrInternal> { // TODO: Check if have any stale or missing ChannelMonitor. + let per_peer_state = self.per_peer_state.read().unwrap(); let logger = WithContext::from(&self.logger, Some(peer_node_id), None, None); let err = || { MsgHandleErrInternal::from_chan_no_close( @@ -8833,6 +8835,55 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ log_trace!(logger, "Got valid {}-byte peer backup from {}", decrypted.len(), peer_node_id); + let mut cursor = io::Cursor::new(decrypted); + match ::read(&mut cursor) { + Ok(mon_list) => { + for mon_holder in mon_list.monitors.iter() { + let peer_state_mutex = + match per_peer_state.get(&mon_holder.counterparty_node_id) { + Some(mutex) => mutex, + None => { + log_debug!( + logger, + "Not able to find peer_state for the counterparty {}, channelId {}", + log_pubkey!(mon_holder.counterparty_node_id), + mon_holder.channel_id + ); + continue; + }, + }; + + let peer_state_lock = peer_state_mutex.lock().unwrap(); + let peer_state = &*peer_state_lock; + + match peer_state.channel_by_id.get(&mon_holder.channel_id) { + Some(chan) => { + if let Some(funded_chan) = chan.as_funded() { + if funded_chan + .get_revoked_counterparty_commitment_transaction_number() + > mon_holder.min_seen_secret + { + panic!( + "Lost channel state for channel {}. + Received peer storage with a more recent state than what our node had. + Use the FundRecoverer to initiate a force close and sweep the funds.", + &mon_holder.channel_id + ); + } + } + }, + None => { + // TODO: Figure out if this channel is so old that we have forgotten about it. + panic!("Lost a channel {}", &mon_holder.channel_id); + }, + } + } + }, + + Err(e) => { + panic!("Wrong serialisation of PeerStorageMonitorHolderList: {}", e); + }, + } Ok(()) } @@ -8858,6 +8909,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ ), ChannelId([0; 32]))); } + #[cfg(not(test))] if msg.data.len() > MAX_PEER_STORAGE_SIZE { log_debug!(logger, "Sending warning to peer and ignoring peer storage request from {} as its over 1KiB", log_pubkey!(counterparty_node_id)); @@ -16151,11 +16203,15 @@ mod tests { #[test] #[rustfmt::skip] + #[should_panic(expected = "Lost a channel ae3367da2c13bc1ceb86bf56418f62828f7ce9d6bfb15a46af5ba1f1ed8b124f")] fn test_peer_storage() { let chanmon_cfgs = create_chanmon_cfgs(2); + let (persister, chain_monitor); let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let nodes_0_deserialized; let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); - let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let nodes_0_serialized = nodes[0].node.encode(); create_announced_chan_between_nodes(&nodes, 0, 1); @@ -16164,25 +16220,37 @@ mod tests { assert_ne!(peer_storage_msg_events_node0.len(), 0); assert_ne!(peer_storage_msg_events_node1.len(), 0); - match peer_storage_msg_events_node0[0] { - MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { - assert_eq!(*node_id, nodes[1].node.get_our_node_id()); - nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg.clone()); + for ps_msg in peer_storage_msg_events_node0 { + match ps_msg { + MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { + assert_eq!(*node_id, nodes[1].node.get_our_node_id()); + nodes[1].node.handle_peer_storage(nodes[0].node.get_our_node_id(), msg.clone()); + } + _ => panic!("Unexpected event"), } - _ => panic!("Unexpected event"), } - match peer_storage_msg_events_node1[0] { - MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { - assert_eq!(*node_id, nodes[0].node.get_our_node_id()); - nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg.clone()); + for ps_msg in peer_storage_msg_events_node1 { + match ps_msg { + MessageSendEvent::SendPeerStorage { ref node_id, ref msg } => { + assert_eq!(*node_id, nodes[0].node.get_our_node_id()); + nodes[0].node.handle_peer_storage(nodes[1].node.get_our_node_id(), msg.clone()); + } + _ => panic!("Unexpected event"), } - _ => panic!("Unexpected event"), } + send_payment(&nodes[0], &vec!(&nodes[1])[..], 1000); + send_payment(&nodes[0], &vec!(&nodes[1])[..], 10000); + send_payment(&nodes[0], &vec!(&nodes[1])[..], 9999); + nodes[0].node.peer_disconnected(nodes[1].node.get_our_node_id()); nodes[1].node.peer_disconnected(nodes[0].node.get_our_node_id()); + // Reload Node! + nodes[0].chain_source.clear_watched_txn_and_outputs(); + reload_node!(nodes[0], test_default_channel_config(), &nodes_0_serialized, &[], persister, chain_monitor, nodes_0_deserialized); + nodes[0].node.peer_connected(nodes[1].node.get_our_node_id(), &msgs::Init { features: nodes[1].node.init_features(), networks: None, remote_network_address: None }, true).unwrap(); @@ -16193,10 +16261,11 @@ mod tests { let node_1_events = nodes[1].node.get_and_clear_pending_msg_events(); assert_eq!(node_1_events.len(), 2); + // Since, node-0 does not have any memory it would not send any message. let node_0_events = nodes[0].node.get_and_clear_pending_msg_events(); - assert_eq!(node_0_events.len(), 2); + assert_eq!(node_0_events.len(), 0); - for msg in node_1_events{ + for msg in node_1_events { if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { nodes[0].node.handle_channel_reestablish(nodes[1].node.get_our_node_id(), msg); assert_eq!(*node_id, nodes[0].node.get_our_node_id()); @@ -16208,35 +16277,8 @@ mod tests { } } - for msg in node_0_events{ - if let MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } = msg { - nodes[1].node.handle_channel_reestablish(nodes[0].node.get_our_node_id(), msg); - assert_eq!(*node_id, nodes[1].node.get_our_node_id()); - } else if let MessageSendEvent::SendPeerStorageRetrieval { ref node_id, ref msg } = msg { - nodes[1].node.handle_peer_storage_retrieval(nodes[0].node.get_our_node_id(), msg.clone()); - assert_eq!(*node_id, nodes[1].node.get_our_node_id()); - } else { - panic!("Unexpected event") - } - } - - let node_1_msg_events = nodes[1].node.get_and_clear_pending_msg_events(); let node_0_msg_events = nodes[0].node.get_and_clear_pending_msg_events(); - - assert_eq!(node_1_msg_events.len(), 3); - assert_eq!(node_0_msg_events.len(), 3); - - for msg in node_1_msg_events { - if let MessageSendEvent::SendChannelReady { ref node_id, .. } = msg { - assert_eq!(*node_id, nodes[0].node.get_our_node_id()); - } else if let MessageSendEvent::SendAnnouncementSignatures { ref node_id, .. } = msg { - assert_eq!(*node_id, nodes[0].node.get_our_node_id()); - } else if let MessageSendEvent::SendChannelUpdate { ref node_id, .. } = msg { - assert_eq!(*node_id, nodes[0].node.get_our_node_id()); - } else { - panic!("Unexpected event") - } - } + assert_eq!(node_0_msg_events.len(), 2); for msg in node_0_msg_events { if let MessageSendEvent::SendChannelReady { ref node_id, .. } = msg { diff --git a/lightning/src/ln/our_peer_storage.rs b/lightning/src/ln/our_peer_storage.rs index 430c9f559f9..29de8e5ebbd 100644 --- a/lightning/src/ln/our_peer_storage.rs +++ b/lightning/src/ln/our_peer_storage.rs @@ -13,8 +13,13 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; +use bitcoin::secp256k1::PublicKey; +use crate::io; +use crate::ln::msgs::DecodeError; +use crate::ln::types::ChannelId; use crate::sign::PeerStorageKey; +use crate::util::ser::{Readable, Writeable, Writer}; use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC; use crate::prelude::*; @@ -146,6 +151,77 @@ fn derive_nonce(key: &PeerStorageKey, random_bytes: &[u8]) -> [u8; 12] { nonce } +/// [`PeerStorageMonitorHolder`] represents a single channel sent over the wire. +/// This would be used inside [`ChannelManager`] to determine +/// if the user has lost channel states so that we can do something about it. +/// +/// The main idea here is to just enable node to figure out that it has lost some data +/// using peer storage backups. +/// +/// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +/// +/// TODO(aditya): Write FundRecoverer to use `monitor_bytes` to drop onchain. +pub(crate) struct PeerStorageMonitorHolder { + /// Channel Id of the channel. + pub(crate) channel_id: ChannelId, + /// Node Id of the channel partner. + pub(crate) counterparty_node_id: PublicKey, + /// Minimum seen secret to determine if we have lost state. + pub(crate) min_seen_secret: u64, + /// Whole serialised ChannelMonitor to recover funds. + pub(crate) monitor_bytes: Vec, +} + +impl Writeable for PeerStorageMonitorHolder { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.channel_id.write(w)?; + self.counterparty_node_id.write(w)?; + self.min_seen_secret.write(w)?; + self.monitor_bytes.write(w) + } +} + +impl Readable for PeerStorageMonitorHolder { + fn read(r: &mut R) -> Result { + let channel_id = Readable::read(r)?; + let counterparty_node_id = Readable::read(r)?; + let min_seen_secret = Readable::read(r)?; + let monitor_bytes = Readable::read(r)?; + + Ok(PeerStorageMonitorHolder { + channel_id, + counterparty_node_id, + min_seen_secret, + monitor_bytes, + }) + } +} + +/// [`PeerStorageMonitorHolderList`] is used to serialise all the channels and send it over wire +/// wrapped inside [`PeerStorage`]. +/// +/// [`PeerStorage`]: crate::ln::msgs::PeerStorage +pub(crate) struct PeerStorageMonitorHolderList { + /// List of all the channels to be sent over the wire. + pub(crate) monitors: Vec, +} + +impl Writeable for PeerStorageMonitorHolderList { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + encode_tlv_stream!(w, { (1, &self.monitors, required_vec) }); + Ok(()) + } +} + +impl Readable for PeerStorageMonitorHolderList { + fn read(r: &mut R) -> Result { + let mut monitors: Option> = None; + decode_tlv_stream!(r, { (1, monitors, optional_vec) }); + + Ok(PeerStorageMonitorHolderList { monitors: monitors.ok_or(DecodeError::InvalidValue)? }) + } +} + #[cfg(test)] mod tests { use crate::ln::our_peer_storage::{derive_nonce, DecryptedOurPeerStorage}; diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index fecdb830fe0..010c98d8ed9 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -1771,6 +1771,11 @@ impl TestChainSource { self.watched_outputs.lock().unwrap().remove(&(outpoint, script_pubkey.clone())); self.watched_txn.lock().unwrap().remove(&(outpoint.txid, script_pubkey)); } + + pub fn clear_watched_txn_and_outputs(&self) { + self.watched_outputs.lock().unwrap().clear(); + self.watched_txn.lock().unwrap().clear(); + } } impl UtxoLookup for TestChainSource {