Add error logs when a ChannelManager as inconsistent monitor state
[rust-lightning] / lightning / src / ln / channelmanager.rs
index 6e18cbfa4a2d7cd2b3950942a30489da140fd5d6..cddb402d987f5243ef903e3f262148d183a72fd2 100644 (file)
@@ -61,9 +61,9 @@ use util::chacha20::{ChaCha20, ChaChaReader};
 use util::logger::Logger;
 use util::errors::APIError;
 
+use prelude::*;
 use core::{cmp, mem};
-use std::cell::RefCell;
-use std::collections::{HashMap, hash_map, HashSet};
+use core::cell::RefCell;
 use std::io::{Cursor, Read};
 use std::sync::{Arc, Condvar, Mutex, MutexGuard, RwLock, RwLockReadGuard};
 use core::sync::atomic::{AtomicUsize, Ordering};
@@ -497,6 +497,7 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
 /// Typically, the block-specific parameters are derived from the best block hash for the network,
 /// as a newly constructed `ChannelManager` will not have created any channels yet. These parameters
 /// are not needed when deserializing a previously constructed `ChannelManager`.
+#[derive(Clone, Copy, PartialEq)]
 pub struct ChainParameters {
        /// The network for determining the `chain_hash` in Lightning messages.
        pub network: Network,
@@ -508,7 +509,7 @@ pub struct ChainParameters {
 }
 
 /// The best known block as identified by its hash and height.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub struct BestBlock {
        block_hash: BlockHash,
        height: u32,
@@ -1933,19 +1934,24 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        // smaller than 500:
        const STATIC_ASSERT: u32 = Self::HALF_MESSAGE_IS_ADDRS - 500;
 
-       /// Generates a signed node_announcement from the given arguments and creates a
-       /// BroadcastNodeAnnouncement event. Note that such messages will be ignored unless peers have
-       /// seen a channel_announcement from us (ie unless we have public channels open).
+       /// Regenerates channel_announcements and generates a signed node_announcement from the given
+       /// arguments, providing them in corresponding events via
+       /// [`get_and_clear_pending_msg_events`], if at least one public channel has been confirmed
+       /// on-chain. This effectively re-broadcasts all channel announcements and sends our node
+       /// announcement to ensure that the lightning P2P network is aware of the channels we have and
+       /// our network addresses.
        ///
-       /// RGB is a node "color" and alias is a printable human-readable string to describe this node
-       /// to humans. They carry no in-protocol meaning.
+       /// `rgb` is a node "color" and `alias` is a printable human-readable string to describe this
+       /// node to humans. They carry no in-protocol meaning.
        ///
-       /// addresses represent the set (possibly empty) of socket addresses on which this node accepts
-       /// incoming connections. These will be broadcast to the network, publicly tying these
-       /// addresses together. If you wish to preserve user privacy, addresses should likely contain
-       /// only Tor Onion addresses.
+       /// `addresses` represent the set (possibly empty) of socket addresses on which this node
+       /// accepts incoming connections. These will be included in the node_announcement, publicly
+       /// tying these addresses together and to this node. If you wish to preserve user privacy,
+       /// addresses should likely contain only Tor Onion addresses.
        ///
-       /// Panics if addresses is absurdly large (more than 500).
+       /// Panics if `addresses` is absurdly large (more than 500).
+       ///
+       /// [`get_and_clear_pending_msg_events`]: MessageSendEventsProvider::get_and_clear_pending_msg_events
        pub fn broadcast_node_announcement(&self, rgb: [u8; 3], alias: [u8; 32], mut addresses: Vec<NetAddress>) {
                let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
 
@@ -1966,14 +1972,37 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                        excess_data: Vec::new(),
                };
                let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]);
+               let node_announce_sig = self.secp_ctx.sign(&msghash, &self.our_network_key);
 
-               let mut channel_state = self.channel_state.lock().unwrap();
-               channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastNodeAnnouncement {
-                       msg: msgs::NodeAnnouncement {
-                               signature: self.secp_ctx.sign(&msghash, &self.our_network_key),
-                               contents: announcement
-                       },
-               });
+               let mut channel_state_lock = self.channel_state.lock().unwrap();
+               let channel_state = &mut *channel_state_lock;
+
+               let mut announced_chans = false;
+               for (_, chan) in channel_state.by_id.iter() {
+                       if let Some(msg) = chan.get_signed_channel_announcement(&self.our_network_key, self.get_our_node_id(), self.genesis_hash.clone()) {
+                               channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
+                                       msg,
+                                       update_msg: match self.get_channel_update(chan) {
+                                               Ok(msg) => msg,
+                                               Err(_) => continue,
+                                       },
+                               });
+                               announced_chans = true;
+                       } else {
+                               // If the channel is not public or has not yet reached funding_locked, check the
+                               // next channel. If we don't yet have any public channels, we'll skip the broadcast
+                               // below as peers may not accept it without channels on chain first.
+                       }
+               }
+
+               if announced_chans {
+                       channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastNodeAnnouncement {
+                               msg: msgs::NodeAnnouncement {
+                                       signature: node_announce_sig,
+                                       contents: announcement
+                               },
+                       });
+               }
        }
 
        /// Processes HTLCs which are pending waiting on random forward delay.
@@ -2292,7 +2321,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
        }
 
        #[cfg(any(test, feature = "_test_utils"))]
-       pub(crate) fn test_process_background_events(&self) {
+       /// Process background events, for functional testing
+       pub fn test_process_background_events(&self) {
                self.process_background_events();
        }
 
@@ -3324,8 +3354,13 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                match channel_state.by_id.entry(chan_id) {
                        hash_map::Entry::Occupied(mut chan) => {
                                if chan.get().get_counterparty_node_id() != *counterparty_node_id {
-                                       // TODO: see issue #153, need a consistent behavior on obnoxious behavior from random node
-                                       return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a message for a channel from the wrong node!".to_owned(), chan_id));
+                                       if chan.get().should_announce() {
+                                               // If the announcement is about a channel of ours which is public, some
+                                               // other peer may simply be forwarding all its gossip to us. Don't provide
+                                               // a scary-looking error message and return Ok instead.
+                                               return Ok(());
+                                       }
+                                       return Err(MsgHandleErrInternal::send_err_msg_no_close("Got a channel_update for a channel from the wrong node - it shouldn't know about our private channels!".to_owned(), chan_id));
                                }
                                try_chan_entry!(self, chan.get_mut().channel_update(&msg), channel_state, chan);
                        },
@@ -3657,7 +3692,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
 
        #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
        pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
-               let events = std::cell::RefCell::new(Vec::new());
+               let events = core::cell::RefCell::new(Vec::new());
                let event_handler = |event| events.borrow_mut().push(event);
                self.process_pending_events(&event_handler);
                events.into_inner()
@@ -4288,244 +4323,89 @@ impl PersistenceNotifier {
 const SERIALIZATION_VERSION: u8 = 1;
 const MIN_SERIALIZATION_VERSION: u8 = 1;
 
-impl Writeable for PendingHTLCInfo {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match &self.routing {
-                       &PendingHTLCRouting::Forward { ref onion_packet, ref short_channel_id } => {
-                               0u8.write(writer)?;
-                               onion_packet.write(writer)?;
-                               short_channel_id.write(writer)?;
-                       },
-                       &PendingHTLCRouting::Receive { ref payment_data, ref incoming_cltv_expiry } => {
-                               1u8.write(writer)?;
-                               payment_data.payment_secret.write(writer)?;
-                               payment_data.total_msat.write(writer)?;
-                               incoming_cltv_expiry.write(writer)?;
-                       },
-               }
-               self.incoming_shared_secret.write(writer)?;
-               self.payment_hash.write(writer)?;
-               self.amt_to_forward.write(writer)?;
-               self.outgoing_cltv_value.write(writer)?;
-               Ok(())
-       }
-}
-
-impl Readable for PendingHTLCInfo {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<PendingHTLCInfo, DecodeError> {
-               Ok(PendingHTLCInfo {
-                       routing: match Readable::read(reader)? {
-                               0u8 => PendingHTLCRouting::Forward {
-                                       onion_packet: Readable::read(reader)?,
-                                       short_channel_id: Readable::read(reader)?,
-                               },
-                               1u8 => PendingHTLCRouting::Receive {
-                                       payment_data: msgs::FinalOnionHopData {
-                                               payment_secret: Readable::read(reader)?,
-                                               total_msat: Readable::read(reader)?,
-                                       },
-                                       incoming_cltv_expiry: Readable::read(reader)?,
-                               },
-                               _ => return Err(DecodeError::InvalidValue),
-                       },
-                       incoming_shared_secret: Readable::read(reader)?,
-                       payment_hash: Readable::read(reader)?,
-                       amt_to_forward: Readable::read(reader)?,
-                       outgoing_cltv_value: Readable::read(reader)?,
-               })
-       }
-}
-
-impl Writeable for HTLCFailureMsg {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match self {
-                       &HTLCFailureMsg::Relay(ref fail_msg) => {
-                               0u8.write(writer)?;
-                               fail_msg.write(writer)?;
-                       },
-                       &HTLCFailureMsg::Malformed(ref fail_msg) => {
-                               1u8.write(writer)?;
-                               fail_msg.write(writer)?;
-                       }
-               }
-               Ok(())
-       }
-}
-
-impl Readable for HTLCFailureMsg {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<HTLCFailureMsg, DecodeError> {
-               match <u8 as Readable>::read(reader)? {
-                       0 => Ok(HTLCFailureMsg::Relay(Readable::read(reader)?)),
-                       1 => Ok(HTLCFailureMsg::Malformed(Readable::read(reader)?)),
-                       _ => Err(DecodeError::InvalidValue),
-               }
-       }
-}
-
-impl Writeable for PendingHTLCStatus {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match self {
-                       &PendingHTLCStatus::Forward(ref forward_info) => {
-                               0u8.write(writer)?;
-                               forward_info.write(writer)?;
-                       },
-                       &PendingHTLCStatus::Fail(ref fail_msg) => {
-                               1u8.write(writer)?;
-                               fail_msg.write(writer)?;
-                       }
-               }
-               Ok(())
-       }
-}
-
-impl Readable for PendingHTLCStatus {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<PendingHTLCStatus, DecodeError> {
-               match <u8 as Readable>::read(reader)? {
-                       0 => Ok(PendingHTLCStatus::Forward(Readable::read(reader)?)),
-                       1 => Ok(PendingHTLCStatus::Fail(Readable::read(reader)?)),
-                       _ => Err(DecodeError::InvalidValue),
-               }
-       }
-}
-
-impl_writeable!(HTLCPreviousHopData, 0, {
-       short_channel_id,
-       outpoint,
-       htlc_id,
-       incoming_packet_shared_secret
-});
-
-impl Writeable for ClaimableHTLC {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               self.prev_hop.write(writer)?;
-               self.value.write(writer)?;
-               self.payment_data.payment_secret.write(writer)?;
-               self.payment_data.total_msat.write(writer)?;
-               self.cltv_expiry.write(writer)
-       }
-}
-
-impl Readable for ClaimableHTLC {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
-               Ok(ClaimableHTLC {
-                       prev_hop: Readable::read(reader)?,
-                       value: Readable::read(reader)?,
-                       payment_data: msgs::FinalOnionHopData {
-                               payment_secret: Readable::read(reader)?,
-                               total_msat: Readable::read(reader)?,
-                       },
-                       cltv_expiry: Readable::read(reader)?,
-               })
-       }
-}
-
-impl Writeable for HTLCSource {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match self {
-                       &HTLCSource::PreviousHopData(ref hop_data) => {
-                               0u8.write(writer)?;
-                               hop_data.write(writer)?;
-                       },
-                       &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat } => {
-                               1u8.write(writer)?;
-                               path.write(writer)?;
-                               session_priv.write(writer)?;
-                               first_hop_htlc_msat.write(writer)?;
-                       }
-               }
-               Ok(())
-       }
-}
-
-impl Readable for HTLCSource {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<HTLCSource, DecodeError> {
-               match <u8 as Readable>::read(reader)? {
-                       0 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
-                       1 => Ok(HTLCSource::OutboundRoute {
-                               path: Readable::read(reader)?,
-                               session_priv: Readable::read(reader)?,
-                               first_hop_htlc_msat: Readable::read(reader)?,
-                       }),
-                       _ => Err(DecodeError::InvalidValue),
-               }
-       }
-}
-
-impl Writeable for HTLCFailReason {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match self {
-                       &HTLCFailReason::LightningError { ref err } => {
-                               0u8.write(writer)?;
-                               err.write(writer)?;
-                       },
-                       &HTLCFailReason::Reason { ref failure_code, ref data } => {
-                               1u8.write(writer)?;
-                               failure_code.write(writer)?;
-                               data.write(writer)?;
-                       }
-               }
-               Ok(())
-       }
-}
-
-impl Readable for HTLCFailReason {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<HTLCFailReason, DecodeError> {
-               match <u8 as Readable>::read(reader)? {
-                       0 => Ok(HTLCFailReason::LightningError { err: Readable::read(reader)? }),
-                       1 => Ok(HTLCFailReason::Reason {
-                               failure_code: Readable::read(reader)?,
-                               data: Readable::read(reader)?,
-                       }),
-                       _ => Err(DecodeError::InvalidValue),
-               }
-       }
-}
-
-impl Writeable for HTLCForwardInfo {
-       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
-               match self {
-                       &HTLCForwardInfo::AddHTLC { ref prev_short_channel_id, ref prev_funding_outpoint, ref prev_htlc_id, ref forward_info } => {
-                               0u8.write(writer)?;
-                               prev_short_channel_id.write(writer)?;
-                               prev_funding_outpoint.write(writer)?;
-                               prev_htlc_id.write(writer)?;
-                               forward_info.write(writer)?;
-                       },
-                       &HTLCForwardInfo::FailHTLC { ref htlc_id, ref err_packet } => {
-                               1u8.write(writer)?;
-                               htlc_id.write(writer)?;
-                               err_packet.write(writer)?;
-                       },
-               }
-               Ok(())
-       }
-}
-
-impl Readable for HTLCForwardInfo {
-       fn read<R: ::std::io::Read>(reader: &mut R) -> Result<HTLCForwardInfo, DecodeError> {
-               match <u8 as Readable>::read(reader)? {
-                       0 => Ok(HTLCForwardInfo::AddHTLC {
-                               prev_short_channel_id: Readable::read(reader)?,
-                               prev_funding_outpoint: Readable::read(reader)?,
-                               prev_htlc_id: Readable::read(reader)?,
-                               forward_info: Readable::read(reader)?,
-                       }),
-                       1 => Ok(HTLCForwardInfo::FailHTLC {
-                               htlc_id: Readable::read(reader)?,
-                               err_packet: Readable::read(reader)?,
-                       }),
-                       _ => Err(DecodeError::InvalidValue),
-               }
-       }
-}
-
-impl_writeable!(PendingInboundPayment, 0, {
-       payment_secret,
-       expiry_time,
-       user_payment_id,
-       payment_preimage,
-       min_value_msat
-});
+impl_writeable_tlv_based_enum!(PendingHTLCRouting,
+       (0, Forward) => {
+               (0, onion_packet),
+               (2, short_channel_id),
+       }, {}, {},
+       (1, Receive) => {
+               (0, payment_data),
+               (2, incoming_cltv_expiry),
+       }, {}, {}
+;);
+
+impl_writeable_tlv_based!(PendingHTLCInfo, {
+       (0, routing),
+       (2, incoming_shared_secret),
+       (4, payment_hash),
+       (6, amt_to_forward),
+       (8, outgoing_cltv_value)
+}, {}, {});
+
+impl_writeable_tlv_based_enum!(HTLCFailureMsg, ;
+       (0, Relay),
+       (1, Malformed),
+);
+impl_writeable_tlv_based_enum!(PendingHTLCStatus, ;
+       (0, Forward),
+       (1, Fail),
+);
+
+impl_writeable_tlv_based!(HTLCPreviousHopData, {
+       (0, short_channel_id),
+       (2, outpoint),
+       (4, htlc_id),
+       (6, incoming_packet_shared_secret)
+}, {}, {});
+
+impl_writeable_tlv_based!(ClaimableHTLC, {
+       (0, prev_hop),
+       (2, value),
+       (4, payment_data),
+       (6, cltv_expiry),
+}, {}, {});
+
+impl_writeable_tlv_based_enum!(HTLCSource,
+       (0, OutboundRoute) => {
+               (0, session_priv),
+               (2, first_hop_htlc_msat),
+       }, {}, {
+               (4, path),
+       };
+       (1, PreviousHopData)
+);
+
+impl_writeable_tlv_based_enum!(HTLCFailReason,
+       (0, LightningError) => {
+               (0, err),
+       }, {}, {},
+       (1, Reason) => {
+               (0, failure_code),
+       }, {}, {
+               (2, data),
+       },
+;);
+
+impl_writeable_tlv_based_enum!(HTLCForwardInfo,
+       (0, AddHTLC) => {
+               (0, forward_info),
+               (2, prev_short_channel_id),
+               (4, prev_htlc_id),
+               (6, prev_funding_outpoint),
+       }, {}, {},
+       (1, FailHTLC) => {
+               (0, htlc_id),
+               (2, err_packet),
+       }, {}, {},
+;);
+
+impl_writeable_tlv_based!(PendingInboundPayment, {
+       (0, payment_secret),
+       (2, expiry_time),
+       (4, user_payment_id),
+       (6, payment_preimage),
+       (8, min_value_msat),
+}, {}, {});
 
 impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable for ChannelManager<Signer, M, T, K, F, L>
        where M::Target: chain::Watch<Signer>,
@@ -4767,6 +4647,11 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
                                                channel.get_cur_counterparty_commitment_transaction_number() < monitor.get_cur_counterparty_commitment_number() ||
                                                channel.get_latest_monitor_update_id() > monitor.get_latest_update_id() {
                                        // If the channel is ahead of the monitor, return InvalidValue:
+                                       log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
+                                       log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.",
+                                               log_bytes!(channel.channel_id()), monitor.get_latest_update_id(), channel.get_latest_monitor_update_id());
+                                       log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
+                                       log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
                                        return Err(DecodeError::InvalidValue);
                                } else if channel.get_cur_holder_commitment_transaction_number() > monitor.get_cur_holder_commitment_number() ||
                                                channel.get_revoked_counterparty_commitment_transaction_number() > monitor.get_min_seen_secret() ||
@@ -4783,6 +4668,9 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
                                        by_id.insert(channel.channel_id(), channel);
                                }
                        } else {
+                               log_error!(args.logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", log_bytes!(channel.channel_id()));
+                               log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
+                               log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
                                return Err(DecodeError::InvalidValue);
                        }
                }
@@ -4989,7 +4877,7 @@ pub mod bench {
        use bitcoin::hashes::sha256::Hash as Sha256;
        use bitcoin::{Block, BlockHeader, Transaction, TxOut};
 
-       use std::sync::Mutex;
+       use std::sync::{Arc, Mutex};
 
        use test::Bencher;
 
@@ -5015,7 +4903,7 @@ pub mod bench {
                let network = bitcoin::Network::Testnet;
                let genesis_hash = bitcoin::blockdata::constants::genesis_block(network).header.block_hash();
 
-               let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())};
+               let tx_broadcaster = test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))};
                let fee_estimator = test_utils::TestFeeEstimator { sat_per_kw: 253 };
 
                let mut config: UserConfig = Default::default();