X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=81789313d290780ca254d910cd26d985a57a06ae;hb=952cee4a168d266d7bdd43d21ac71a3e3de46a53;hp=699941586e653927d15201e44e1499c9d7b2786e;hpb=84fa127661ff09de94ac6129dd0790d6de79f8b7;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 69994158..81789313 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -42,7 +42,7 @@ use chain::transaction::{OutPoint, TransactionData}; // construct one themselves. use ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use ln::channel::{Channel, ChannelError, ChannelUpdateStatus, UpdateFulfillCommitFetch}; -use ln::features::{InitFeatures, NodeFeatures}; +use ln::features::{ChannelTypeFeatures, InitFeatures, NodeFeatures}; use routing::router::{PaymentParameters, Route, RouteHop, RoutePath, RouteParameters}; use ln::msgs; use ln::msgs::NetAddress; @@ -53,7 +53,7 @@ use util::config::UserConfig; use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use util::{byte_utils, events}; use util::scid_utils::fake_scid; -use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer}; +use util::ser::{BigSize, FixedLengthReader, Readable, ReadableArgs, MaybeReadable, Writeable, Writer, VecWriter}; use util::logger::{Level, Logger}; use util::errors::APIError; @@ -1200,6 +1200,10 @@ pub struct ChannelDetails { /// Note that, if this has been set, `channel_id` will be equivalent to /// `funding_txo.unwrap().to_channel_id()`. pub funding_txo: Option, + /// The features which this channel operates with. See individual features for more info. + /// + /// `None` until negotiation completes and the channel type is finalized. + pub channel_type: Option, /// The position of the funding transaction in the chain. None if the funding transaction has /// not yet been confirmed and the channel fully opened. /// @@ -1214,6 +1218,9 @@ pub struct ChannelDetails { /// counterparty will recognize the alias provided here in place of the [`short_channel_id`] /// when they see a payment to be routed to us. /// + /// Our counterparty may choose to rotate this value at any time, though will always recognize + /// previous values for inbound payment forwarding. + /// /// [`short_channel_id`]: Self::short_channel_id pub inbound_scid_alias: Option, /// The value, in satoshis, of this channel as appears in the funding output @@ -1302,9 +1309,12 @@ pub struct ChannelDetails { } impl ChannelDetails { - /// Gets the SCID which should be used to identify this channel for inbound payments. This - /// should be used for providing invoice hints or in any other context where our counterparty - /// will forward a payment to us. + /// Gets the current SCID which should be used to identify this channel for inbound payments. + /// This should be used for providing invoice hints or in any other context where our + /// counterparty will forward a payment to us. + /// + /// This is either the [`ChannelDetails::inbound_scid_alias`], if set, or the + /// [`ChannelDetails::short_channel_id`]. See those for more information. pub fn get_inbound_payment_scid(&self) -> Option { self.inbound_scid_alias.or(self.short_channel_id) } @@ -1922,6 +1932,9 @@ impl ChannelMana forwarding_info: channel.counterparty_forwarding_info(), }, funding_txo: channel.get_funding_txo(), + // Note that accept_channel (or open_channel) is always the first message, so + // `have_received_message` indicates that type negotiation has completed. + channel_type: if channel.have_received_message() { Some(channel.get_channel_type().clone()) } else { None }, short_channel_id: channel.get_short_channel_id(), inbound_scid_alias: channel.latest_inbound_scid_alias(), channel_value_satoshis: channel.get_value_satoshis(), @@ -2406,15 +2419,19 @@ impl ChannelMana }; let (chan_update_opt, forwardee_cltv_expiry_delta) = if let Some(forwarding_id) = forwarding_id_opt { let chan = channel_state.as_mut().unwrap().by_id.get_mut(&forwarding_id).unwrap(); - // Leave channel updates as None for private channels. - let chan_update_opt = if chan.should_announce() { - Some(self.get_channel_update_for_unicast(chan).unwrap()) } else { None }; if !chan.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels { // Note that the behavior here should be identical to the above block - we // should NOT reveal the existence or non-existence of a private channel if // we don't allow forwards outbound over them. - break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None)); + break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None)); + } + if chan.get_channel_type().supports_scid_privacy() && *short_channel_id != chan.outbound_scid_alias() { + // `option_scid_alias` (referred to in LDK as `scid_privacy`) means + // "refuse to forward unless the SCID alias was used", so we pretend + // we don't have the channel here. + break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None)); } + let chan_update_opt = self.get_channel_update_for_onion(*short_channel_id, chan).ok(); // Note that we could technically not return an error yet here and just hope // that the connection is reestablished or monitor updated by the time we get @@ -2464,21 +2481,22 @@ impl ChannelMana break None; } { - let mut res = Vec::with_capacity(8 + 128); + let mut res = VecWriter(Vec::with_capacity(chan_update.serialized_length() + 8 + 2)); if let Some(chan_update) = chan_update { if code == 0x1000 | 11 || code == 0x1000 | 12 { - res.extend_from_slice(&byte_utils::be64_to_array(msg.amount_msat)); + msg.amount_msat.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 13 { - res.extend_from_slice(&byte_utils::be32_to_array(msg.cltv_expiry)); + msg.cltv_expiry.write(&mut res).expect("Writes cannot fail"); } else if code == 0x1000 | 20 { // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791 - res.extend_from_slice(&byte_utils::be16_to_array(0)); + 0u16.write(&mut res).expect("Writes cannot fail"); } - res.extend_from_slice(&chan_update.encode_with_len()[..]); + (chan_update.serialized_length() as u16).write(&mut res).expect("Writes cannot fail"); + chan_update.write(&mut res).expect("Writes cannot fail"); } - return_err!(err, code, &res[..]); + return_err!(err, code, &res.0[..]); } } } @@ -2514,6 +2532,10 @@ impl ChannelMana Some(id) => id, }; + self.get_channel_update_for_onion(short_channel_id, chan) + } + fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel) -> Result { + log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.channel_id())); let were_node_one = PublicKey::from_secret_key(&self.secp_ctx, &self.our_network_key).serialize()[..] < chan.get_counterparty_node_id().serialize()[..]; let unsigned = msgs::UnsignedChannelUpdate { @@ -3203,9 +3225,9 @@ impl ChannelMana } else { panic!("Stated return value requirements in send_htlc() were not met"); } - let chan_update = self.get_channel_update_for_unicast(chan.get()).unwrap(); + let (failure_code, data) = self.get_htlc_temp_fail_err_and_data(0x1000|7, short_chan_id, chan.get()); failed_forwards.push((htlc_source, payment_hash, - HTLCFailReason::Reason { failure_code: 0x1000 | 7, data: chan_update.encode_with_len() } + HTLCFailReason::Reason { failure_code, data } )); continue; }, @@ -3701,6 +3723,51 @@ impl ChannelMana } else { false } } + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + /// + /// This is for failures on the channel on which the HTLC was *received*, not failures + /// forwarding + fn get_htlc_inbound_temp_fail_err_and_data(&self, desired_err_code: u16, chan: &Channel) -> (u16, Vec) { + // We can't be sure what SCID was used when relaying inbound towards us, so we have to + // guess somewhat. If its a public channel, we figure best to just use the real SCID (as + // we're not leaking that we have a channel with the counterparty), otherwise we try to use + // an inbound SCID alias before the real SCID. + let scid_pref = if chan.should_announce() { + chan.get_short_channel_id().or(chan.latest_inbound_scid_alias()) + } else { + chan.latest_inbound_scid_alias().or(chan.get_short_channel_id()) + }; + if let Some(scid) = scid_pref { + self.get_htlc_temp_fail_err_and_data(desired_err_code, scid, chan) + } else { + (0x4000|10, Vec::new()) + } + } + + + /// Gets an HTLC onion failure code and error data for an `UPDATE` error, given the error code + /// that we want to return and a channel. + fn get_htlc_temp_fail_err_and_data(&self, desired_err_code: u16, scid: u64, chan: &Channel) -> (u16, Vec) { + debug_assert_eq!(desired_err_code & 0x1000, 0x1000); + if let Ok(upd) = self.get_channel_update_for_onion(scid, chan) { + let mut enc = VecWriter(Vec::with_capacity(upd.serialized_length() + 4)); + if desired_err_code == 0x1000 | 20 { + // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791 + 0u16.write(&mut enc).expect("Writes cannot fail"); + } + (upd.serialized_length() as u16).write(&mut enc).expect("Writes cannot fail"); + upd.write(&mut enc).expect("Writes cannot fail"); + (desired_err_code, enc.0) + } else { + // If we fail to get a unicast channel_update, it implies we don't yet have an SCID, + // which means we really shouldn't have gotten a payment to be forwarded over this + // channel yet, or if we did it's from a route hint. Either way, returning an error of + // PERM|no_such_channel should be fine. + (0x4000|10, Vec::new()) + } + } + // Fail a list of HTLCs that were just freed from the holding cell. The HTLCs need to be // failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to // be surfaced to the user. @@ -3711,11 +3778,7 @@ impl ChannelMana let (failure_code, onion_failure_data) = match self.channel_state.lock().unwrap().by_id.entry(channel_id) { hash_map::Entry::Occupied(chan_entry) => { - if let Ok(upd) = self.get_channel_update_for_unicast(&chan_entry.get()) { - (0x1000|7, upd.encode_with_len()) - } else { - (0x4000|10, Vec::new()) - } + self.get_htlc_inbound_temp_fail_err_and_data(0x1000|7, &chan_entry.get()) }, hash_map::Entry::Vacant(_) => (0x4000|10, Vec::new()) }; @@ -4228,10 +4291,12 @@ impl ChannelMana // channel_update later through the announcement_signatures process for public // channels, but there's no reason not to just inform our counterparty of our fees // now. - Some(events::MessageSendEvent::SendChannelUpdate { - node_id: channel.get().get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(channel.get()).unwrap(), - }) + if let Ok(msg) = self.get_channel_update_for_unicast(channel.get()) { + Some(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get().get_counterparty_node_id(), + msg, + }) + } else { None } } else { None }; chan_restoration_res = handle_chan_restoration_locked!(self, channel_lock, channel_state, channel, updates.raa, updates.commitment_update, updates.order, None, updates.accepted_htlcs, updates.funding_broadcastable, updates.funding_locked, updates.announcement_sigs); if let Some(upd) = channel_update { @@ -4315,6 +4380,7 @@ impl ChannelMana counterparty_node_id: counterparty_node_id.clone(), funding_satoshis: msg.funding_satoshis, push_msat: msg.push_msat, + channel_type: channel.get_channel_type().clone(), } ); } @@ -4466,10 +4532,12 @@ impl ChannelMana // channel_update here if the channel is not public, i.e. we're not sending an // announcement_signatures. log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().channel_id())); - channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { - node_id: counterparty_node_id.clone(), - msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: counterparty_node_id.clone(), + msg, + }); + } } Ok(()) }, @@ -4600,28 +4668,8 @@ impl ChannelMana match pending_forward_info { PendingHTLCStatus::Forward(PendingHTLCInfo { ref incoming_shared_secret, .. }) => { let reason = if (error_code & 0x1000) != 0 { - if let Ok(upd) = self.get_channel_update_for_unicast(chan) { - onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{ - let mut res = Vec::with_capacity(8 + 128); - // TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791 - if error_code == 0x1000 | 20 { - res.extend_from_slice(&byte_utils::be16_to_array(0)); - } - res.extend_from_slice(&upd.encode_with_len()[..]); - res - }[..]) - } else { - // The only case where we'd be unable to - // successfully get a channel update is if the - // channel isn't in the fully-funded state yet, - // implying our counterparty is trying to route - // payments over the channel back to themselves - // (because no one else should know the short_id - // is a lightning channel yet). We should have - // no problem just calling this - // unknown_next_peer (0x4000|10). - onion_utils::build_first_hop_failure_packet(incoming_shared_secret, 0x4000|10, &[]) - } + let (real_code, error_data) = self.get_htlc_inbound_temp_fail_err_and_data(error_code, chan); + onion_utils::build_first_hop_failure_packet(incoming_shared_secret, real_code, &error_data) } else { onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &[]) }; @@ -4943,10 +4991,12 @@ impl ChannelMana // If the channel is in a usable state (ie the channel is not being shut // down), send a unicast channel_update to our counterparty to make sure // they have the latest channel parameters. - channel_update = Some(events::MessageSendEvent::SendChannelUpdate { - node_id: chan.get().get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(chan.get()).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) { + channel_update = Some(events::MessageSendEvent::SendChannelUpdate { + node_id: chan.get().get_counterparty_node_id(), + msg, + }); + } } let need_lnd_workaround = chan.get_mut().workaround_lnd_bug_4006.take(); chan_restoration_res = handle_chan_restoration_locked!( @@ -5239,6 +5289,8 @@ impl ChannelMana /// Legacy version of [`create_inbound_payment`]. Use this method if you wish to share /// serialized state with LDK node(s) running 0.0.103 and earlier. /// + /// May panic if `invoice_expiry_delta_secs` is greater than one year. + /// /// # Note /// This method is deprecated and will be removed soon. /// @@ -5279,8 +5331,6 @@ impl ChannelMana /// If you need exact expiry semantics, you should enforce them upon receipt of /// [`PaymentReceived`]. /// - /// May panic if `invoice_expiry_delta_secs` is greater than one year. - /// /// Note that invoices generated for inbound payments should have their `min_final_cltv_expiry` /// set to at least [`MIN_FINAL_CLTV_EXPIRY`]. /// @@ -5303,6 +5353,8 @@ impl ChannelMana /// Legacy version of [`create_inbound_payment_for_hash`]. Use this method if you wish to share /// serialized state with LDK node(s) running 0.0.103 and earlier. /// + /// May panic if `invoice_expiry_delta_secs` is greater than one year. + /// /// # Note /// This method is deprecated and will be removed soon. /// @@ -5609,20 +5661,21 @@ where let res = f(channel); if let Ok((funding_locked_opt, mut timed_out_pending_htlcs, announcement_sigs)) = res { for (source, payment_hash) in timed_out_pending_htlcs.drain(..) { - let chan_update = self.get_channel_update_for_unicast(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe - timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { - failure_code: 0x1000 | 14, // expiry_too_soon, or at least it is now - data: chan_update, + let (failure_code, data) = self.get_htlc_inbound_temp_fail_err_and_data(0x1000|14 /* expiry_too_soon */, &channel); + timed_out_htlcs.push((source, payment_hash, HTLCFailReason::Reason { + failure_code, data, })); } if let Some(funding_locked) = funding_locked_opt { send_funding_locked!(short_to_id, pending_msg_events, channel, funding_locked); if channel.is_usable() { log_trace!(self.logger, "Sending funding_locked with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.channel_id())); - pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { - node_id: channel.get_counterparty_node_id(), - msg: self.get_channel_update_for_unicast(channel).unwrap(), - }); + if let Ok(msg) = self.get_channel_update_for_unicast(channel) { + pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate { + node_id: channel.get_counterparty_node_id(), + msg, + }); + } } else { log_trace!(self.logger, "Sending funding_locked WITHOUT channel_update for {}", log_bytes!(channel.channel_id())); } @@ -5956,6 +6009,23 @@ impl } } } else { + { + // First check if we can advance the channel type and try again. + let mut channel_state = self.channel_state.lock().unwrap(); + if let Some(chan) = channel_state.by_id.get_mut(&msg.channel_id) { + if chan.get_counterparty_node_id() != *counterparty_node_id { + return; + } + if let Ok(msg) = chan.maybe_handle_error_without_close(self.genesis_hash) { + channel_state.pending_msg_events.push(events::MessageSendEvent::SendOpenChannel { + node_id: *counterparty_node_id, + msg, + }); + return; + } + } + } + // Untrusted messages from peer, we throw away the error if id points to a non-existent channel let _ = self.force_close_channel_with_peer(&msg.channel_id, Some(counterparty_node_id), Some(&msg.data)); } @@ -6052,6 +6122,7 @@ impl_writeable_tlv_based!(ChannelCounterparty, { impl_writeable_tlv_based!(ChannelDetails, { (1, inbound_scid_alias, option), (2, channel_id, required), + (3, channel_type, option), (4, counterparty, required), (6, funding_txo, option), (8, short_channel_id, option), @@ -6957,6 +7028,7 @@ mod tests { use util::errors::APIError; use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use util::test_utils; + use chain::keysinterface::KeysInterface; #[cfg(feature = "std")] #[test] @@ -7210,6 +7282,7 @@ mod tests { let nodes = create_network(2, &node_cfgs, &node_chanmgrs); create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); let scorer = test_utils::TestScorer::with_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); // To start (1), send a regular payment but don't claim it. let expected_route = [&nodes[1]]; @@ -7223,7 +7296,7 @@ mod tests { }; let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -7254,7 +7327,7 @@ mod tests { let payment_preimage = PaymentPreimage([42; 32]); let route = find_route( &nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None, - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap(); check_added_monitors!(nodes[0], 1); @@ -7315,9 +7388,10 @@ mod tests { let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::with_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -7358,9 +7432,10 @@ mod tests { let network_graph = nodes[0].network_graph; let first_hops = nodes[0].node.list_usable_channels(); let scorer = test_utils::TestScorer::with_penalty(0); + let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes(); let route = find_route( &payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::>()), - nodes[0].logger, &scorer + nodes[0].logger, &scorer, &random_seed_bytes ).unwrap(); let test_preimage = PaymentPreimage([42; 32]); @@ -7444,7 +7519,7 @@ mod tests { pub mod bench { use chain::Listen; use chain::chainmonitor::{ChainMonitor, Persist}; - use chain::keysinterface::{KeysManager, InMemorySigner}; + use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner}; use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage}; use ln::features::{InitFeatures, InvoiceFeatures}; use ln::functional_test_utils::*; @@ -7453,7 +7528,7 @@ pub mod bench { use routing::router::{PaymentParameters, get_route}; use util::test_utils; use util::config::UserConfig; - use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose}; + use util::events::{Event, MessageSendEvent, MessageSendEventsProvider}; use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; @@ -7561,8 +7636,11 @@ pub mod bench { let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id()) .with_features(InvoiceFeatures::known()); let scorer = test_utils::TestScorer::with_penalty(0); - let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph, - Some(&usable_channels.iter().map(|r| r).collect::>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap(); + let seed = [3u8; 32]; + let keys_manager = KeysManager::new(&seed, 42, 42); + let random_seed_bytes = keys_manager.get_secure_random_bytes(); + let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph.read_only(), + Some(&usable_channels.iter().map(|r| r).collect::>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer, &random_seed_bytes).unwrap(); let mut payment_preimage = PaymentPreimage([0; 32]); payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());